diff --git a/Makefile b/Makefile new file mode 100644 index 000000000..d9ac043f6 --- /dev/null +++ b/Makefile @@ -0,0 +1,92 @@ +DOCKER_EXEC = docker compose exec api +PHPUNIT = $(DOCKER_EXEC) vendor/bin/phpunit --bootstrap tests/autoload.php --testdox + +# Events-shape migration runners. Dry-run by default; pass APPLY=1 to write. +MIGRATE_EVENTS = $(DOCKER_EXEC) php management/events +APPLY_FLAG = $(if $(APPLY),--apply,) + +.PHONY: help test event-tests regression-tests test-filter test-file shell exec restart-movies db-shell \ + migrate-events migrate-screenshots migrate-movies migrate-client-states requeue-movie + +.DEFAULT_GOAL := help + +help: + @echo "Available commands:" + @echo " make test - Run all unit tests" + @echo " make event-tests - Run EventsApi tests" + @echo " make regression-tests - Run regression tests" + @echo " make test-filter f=... - Run tests whose name matches the PHPUnit --filter regex" + @echo " e.g. make test-filter f=testItShouldFallBack" + @echo " e.g. make test-filter f=LegacyEventString" + @echo " make test-file p=... - Run a single test file or directory under tests/unit_tests" + @echo " e.g. make test-file p=tests/unit_tests/validation/LegacyEventStringTest.php" + @echo " e.g. make test-file p=tests/unit_tests/events" + @echo " make shell - Open bash shell in api container" + @echo " make exec cmd=\"...\" - Run a command in api container" + @echo " make restart-movies - Restart movies container" + @echo " make db-shell - Open MySQL shell" + @echo " make migrate-events - Events-shape migration, all tables (dry-run)" + @echo " lists unique tree=>shape conversions, writes nothing" + @echo " add APPLY=1 to actually write, e.g. make migrate-events APPLY=1" + @echo " make migrate-screenshots - Only the screenshots table (dry-run; APPLY=1 to write)" + @echo " make migrate-movies - Only the movies table (dry-run; APPLY=1 to write)" + @echo " make migrate-client-states - Only the client_states table (dry-run; APPLY=1 to write)" + @echo " make requeue-movie id=... - Rebuild a movie by its public id (force=true)" + @echo " e.g. make requeue-movie id=hl66n" + +shell: + $(DOCKER_EXEC) bash + +exec: + $(DOCKER_EXEC) $(cmd) + +test: + $(PHPUNIT) tests/unit_tests + +event-tests: + $(PHPUNIT) tests/unit_tests/events/ + +regression-tests: + $(PHPUNIT) tests/unit_tests/regression/ + +# Run only tests whose method name matches the given regex. +# Usage: make test-filter f= (also accepts: filter=, FILTER=) +test-filter: + @if [ -z "$(f)$(filter)$(FILTER)" ]; then \ + echo "Error: pass a filter, e.g. make test-filter f=testItShouldFallBack"; exit 1; \ + fi + $(PHPUNIT) tests/unit_tests --filter '$(f)$(filter)$(FILTER)' + +# Run a single test file (or limit to a sub-directory). +# Usage: make test-file p=tests/unit_tests/validation/LegacyEventStringTest.php +test-file: + @if [ -z "$(p)$(path)$(PATH_)" ]; then \ + echo "Error: pass a path, e.g. make test-file p=tests/unit_tests/validation/LegacyEventStringTest.php"; exit 1; \ + fi + $(PHPUNIT) '$(p)$(path)$(PATH_)' + +restart-movies: + docker compose restart movies + +db-shell: + docker compose exec database mariadb -u helioviewer -phelioviewer helioviewer + +# Events-shape migration. Each target is dry-run by default (lists unique +# tree=>shape conversions, no writes); pass APPLY=1 to perform the UPDATEs. +migrate-screenshots: + $(MIGRATE_EVENTS)/migrate_screenshots_events_shape.php $(APPLY_FLAG) + +migrate-movies: + $(MIGRATE_EVENTS)/migrate_movies_events_shape.php $(APPLY_FLAG) + +migrate-client-states: + $(MIGRATE_EVENTS)/migrate_client_states_events_shape.php $(APPLY_FLAG) + +migrate-events: migrate-screenshots migrate-movies migrate-client-states + +# Rebuild a movie by its public id (e.g. hl66n). force=true so it re-queues even +# when the cached file already exists. Usage: make requeue-movie id=hl66n +requeue-movie: + @if [ -z "$(id)" ]; then echo "Error: pass id=, e.g. make requeue-movie id=hl66n"; exit 1; fi + $(DOCKER_EXEC) curl -s "http://localhost/?action=reQueueMovie&id=$(id)&force=true" + @echo diff --git a/README.md b/README.md index 6537a51f0..df924f1ff 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,25 @@ If you wish to run your own local copy of Helioviewer.org, you have 2 options. - Through the development [container](https://hub.docker.com/r/dgarciabriseno/helioviewer.org-docker). - Manual Installation with instructions [here](https://helioviewer-project.github.io/install/). +## Development + +A `Makefile` wraps the common `docker compose` workflows for the API container. +Run `make help` for the full list. The most-used targets: + +| Command | What it does | +| --- | --- | +| `make test` | Run all unit tests | +| `make event-tests` | Run the events test suite | +| `make regression-tests` | Run the regression suite | +| `make test-file p=` | Run a single test file or directory, e.g. `make test-file p=tests/unit_tests/events` | +| `make test-filter f=` | Run tests whose method name matches a regex, e.g. `make test-filter f=testItShouldFallBack` | +| `make shell` | Open a bash shell in the `api` container | +| `make exec cmd="..."` | Run an arbitrary command in the `api` container | +| `make restart-movies` | Restart the `movies` worker container | +| `make db-shell` | Open a MySQL shell against the dev database | + +All targets assume the development container is running (`docker compose up`). + ## License Helioviewer.org is licensed under the Mozilla Public License. diff --git a/docroot/resources/images/eventMarkers/MC.png b/docroot/resources/images/eventMarkers/MC.png new file mode 100644 index 000000000..50624e55f Binary files /dev/null and b/docroot/resources/images/eventMarkers/MC.png differ diff --git a/docroot/resources/images/eventMarkers/MC@2x.png b/docroot/resources/images/eventMarkers/MC@2x.png new file mode 100644 index 000000000..70422b297 Binary files /dev/null and b/docroot/resources/images/eventMarkers/MC@2x.png differ diff --git a/docroot/schema/client_state.schema.json b/docroot/schema/client_state.schema.json index 930d32761..13cafc6a5 100644 --- a/docroot/schema/client_state.schema.json +++ b/docroot/schema/client_state.schema.json @@ -10,8 +10,11 @@ "centerX": { "type": "number" }, "centerY": { "type": "number" }, "imageScale": { "type": "number" }, - "eventLayers": { - "$ref": "https://api.helioviewer.org/schema/event_layers.schema.json" + "event_selections": { + "$ref": "https://api.helioviewer.org/schema/event_selections.schema.json" + }, + "event_visibility_selections": { + "$ref": "https://api.helioviewer.org/schema/event_visibility_selections.schema.json" }, "imageLayers": { "type": "array", @@ -29,7 +32,8 @@ "centerX", "centerY", "imageScale", - "eventLayers", + "event_selections", + "event_visibility_selections", "imageLayers", "celestialBodies" ] diff --git a/docroot/schema/event_layers.schema.json b/docroot/schema/event_layers.schema.json index dab6845f1..b809ac9f0 100644 --- a/docroot/schema/event_layers.schema.json +++ b/docroot/schema/event_layers.schema.json @@ -16,7 +16,8 @@ "enum": [ "HEK", "CCMC", - "RHESSI" + "RHESSI", + "WSA" ] }, "visible": { "type": "boolean" }, @@ -53,7 +54,7 @@ }, "event_instances": { "type": "array", - "maxItems": 30, + "maxItems": 200, "items": { "type": "string", "pattern": "^[a-zA-Z0-9]{2,3}--[a-zA-Z0-9_ +\\\\()\\-]{1,50}--[a-zA-Z0-9_.\\()+]+$", @@ -66,6 +67,7 @@ }, "layers_v2": { "type": "array", + "maxItems": 200, "items": { "type": "string", "minLength": 1, diff --git a/docroot/schema/event_selections.schema.json b/docroot/schema/event_selections.schema.json new file mode 100644 index 000000000..942e1d56d --- /dev/null +++ b/docroot/schema/event_selections.schema.json @@ -0,0 +1,14 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://api.helioviewer.org/schema/event_selections.schema.json", + "title": "Event Selections", + "description": "Selection paths for the events API. Paths are canonical SOURCE>>Label[>>FRM[>>...]] strings; variable depth is allowed. Upstream cap is 200 selections per request.", + "type": "array", + "minItems": 0, + "maxItems": 200, + "items": { + "type": "string", + "minLength": 1, + "maxLength": 600 + } +} diff --git a/docroot/schema/event_visibility_selections.schema.json b/docroot/schema/event_visibility_selections.schema.json new file mode 100644 index 000000000..79d9d4a48 --- /dev/null +++ b/docroot/schema/event_visibility_selections.schema.json @@ -0,0 +1,24 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://api.helioviewer.org/schema/event_visibility_selections.schema.json", + "title": "Event Visibility Selections", + "description": "Per-source marker and label visibility flags. Keys are canonical event source names; unknown sources are rejected. Both flags are optional per source and default to true server-side when omitted.", + "type": "object", + "additionalProperties": false, + "properties": { + "HEK": { "$ref": "#/$defs/source_flags" }, + "CCMC": { "$ref": "#/$defs/source_flags" }, + "RHESSI": { "$ref": "#/$defs/source_flags" }, + "WSA": { "$ref": "#/$defs/source_flags" } + }, + "$defs": { + "source_flags": { + "type": "object", + "additionalProperties": false, + "properties": { + "marker_visibility": { "type": "boolean" }, + "label_visibility": { "type": "boolean" } + } + } + } +} diff --git a/docroot/schema/events_data_coverage.schema.json b/docroot/schema/events_data_coverage.schema.json new file mode 100644 index 000000000..b6fc714fb --- /dev/null +++ b/docroot/schema/events_data_coverage.schema.json @@ -0,0 +1,17 @@ +{ + "$schema": "https://json-schema.org/draft/2020-12/schema", + "$id": "https://api.helioviewer.org/schema/events_data_coverage.schema.json", + "title": "eventsDataCoverage request body", + "description": "Selection paths for the events timeline. Paths are canonical SOURCE>>Label[>>FRM[>>...]] strings; variable depth is allowed. At least one selection is required.", + "type": "object", + "additionalProperties": false, + "required": ["event_selections"], + "properties": { + "event_selections": { + "allOf": [ + { "$ref": "https://api.helioviewer.org/schema/event_selections.schema.json" }, + { "minItems": 1 } + ] + } + } +} diff --git a/docroot/schema/post_movie.schema.json b/docroot/schema/post_movie.schema.json index 4d6768892..9700d326c 100644 --- a/docroot/schema/post_movie.schema.json +++ b/docroot/schema/post_movie.schema.json @@ -19,8 +19,11 @@ "maxLength": 1000, "pattern": "^[\\_\\w\\]\\[,\\-:\\.\\+ ]+$" }, - "eventsState": { - "$ref": "https://api.helioviewer.org/schema/event_layers.schema.json" + "event_selections": { + "$ref": "https://api.helioviewer.org/schema/event_selections.schema.json" + }, + "event_visibility_selections": { + "$ref": "https://api.helioviewer.org/schema/event_visibility_selections.schema.json" }, "imageScale": { "type": "number" }, "format": { diff --git a/docroot/schema/post_screenshot.schema.json b/docroot/schema/post_screenshot.schema.json index 6092c2fa9..40c3e20bd 100644 --- a/docroot/schema/post_screenshot.schema.json +++ b/docroot/schema/post_screenshot.schema.json @@ -17,8 +17,11 @@ "maxLength": 1000, "pattern": "^[\\_\\w\\]\\[,\\-:\\.\\+ ]+$" }, - "eventsState": { - "$ref": "https://api.helioviewer.org/schema/event_layers.schema.json" + "event_selections": { + "$ref": "https://api.helioviewer.org/schema/event_selections.schema.json" + }, + "event_visibility_selections": { + "$ref": "https://api.helioviewer.org/schema/event_visibility_selections.schema.json" }, "scale": { "type": "boolean" }, "scaleType": { diff --git a/docs/src/openapi.yaml b/docs/src/openapi.yaml index e887c8be1..0a85be330 100644 --- a/docs/src/openapi.yaml +++ b/docs/src/openapi.yaml @@ -542,17 +542,9 @@ paths: "endTime": "2010-03-04T12:12:12Z", "imageScale": 21.04, "layers": "[3,1,100]", - "eventsState": { - "tree_HEK": { - "labels_visible": true, - "layers": [ - { - "event_type": "flare", - "frms": ["frm10", "frm20"], - "event_instances": ["flare--frm1--event1", "flare--frm2--event2"] - } - ] - } + "event_selections": ["HEK>>Active Region", "HEK>>Flare>>SWPC"], + "event_visibility_selections": { + "HEK": { "marker_visibility": true, "label_visibility": true } }, "x1": -5000, "y1": -5000, @@ -829,17 +821,32 @@ paths: - $ref: '#/components/parameters/screenshotDate' - $ref: '#/components/parameters/screenshotImageScale' - $ref: '#/components/parameters/screenshotLayers' + - name: event_selections + in: query + required: false + description: > + Canonical event selections as a semicolon-separated list of + ``SOURCE>>Label[>>FRM]`` paths, e.g. + ``HEK>>Active Region;CCMC>>DONKI``. Takes precedence over the legacy + ``events`` bracket-string when both are supplied. URL-encode the + value (``;`` and ``>>`` in particular). + schema: + type: string - name: events in: query required: false description: > - Feature/event annotations (e.g. `[AR,HMI_HARP;SPoCA,1],[CH,all,1]`). + Legacy feature/event annotations as a bracket-string, e.g. + ``[AR,HMI_HARP;SPoCA,1],[CH,all,1]``. Superseded by + ``event_selections``; used only when ``event_selections`` is absent. schema: type: string - name: eventLabels in: query required: false - description: Annotate each event marker with a text label. + description: > + Annotate each event marker with a text label. Applies to whichever + of ``event_selections`` / ``events`` is used. schema: type: boolean - $ref: '#/components/parameters/screenshotScale' @@ -2160,6 +2167,42 @@ components: full: type: string + EventSelections: + type: array + maxItems: 200 + description: > + Canonical event selection paths, each a ``SOURCE>>Label[>>FRM[>>...]]`` + string (variable depth allowed). Upstream cap is 200 selections per + request. + items: + type: string + minLength: 1 + maxLength: 600 + example: ["HEK>>Active Region", "CCMC>>DONKI"] + + EventVisibilitySelections: + type: object + additionalProperties: false + description: > + Per-source marker/label visibility. Keys are canonical event source + names; both flags are optional per source and default to true + server-side when omitted. + properties: + HEK: { $ref: '#/components/schemas/EventSourceFlags' } + CCMC: { $ref: '#/components/schemas/EventSourceFlags' } + RHESSI: { $ref: '#/components/schemas/EventSourceFlags' } + WSA: { $ref: '#/components/schemas/EventSourceFlags' } + example: + HEK: { marker_visibility: true, label_visibility: false } + CCMC: { marker_visibility: true, label_visibility: true } + + EventSourceFlags: + type: object + additionalProperties: false + properties: + marker_visibility: { type: boolean } + label_visibility: { type: boolean } + PostMovieRequest: type: object required: [startTime, endTime, imageScale, layers] @@ -2175,11 +2218,10 @@ components: layers: type: string example: "[3,1,100]" - eventsState: - type: object - description: > - Optional feature/event annotation state. See the Helioviewer - events state documentation for structure details. + event_selections: + $ref: '#/components/schemas/EventSelections' + event_visibility_selections: + $ref: '#/components/schemas/EventVisibilitySelections' imageScale: type: number format: double @@ -2263,9 +2305,10 @@ components: layers: type: string example: "[3,1,100]" - eventsState: - type: object - description: Optional feature/event annotation state. + event_selections: + $ref: '#/components/schemas/EventSelections' + event_visibility_selections: + $ref: '#/components/schemas/EventVisibilitySelections' scale: type: boolean default: false diff --git a/management/events/events_shape.php b/management/events/events_shape.php new file mode 100644 index 000000000..42417a692 --- /dev/null +++ b/management/events/events_shape.php @@ -0,0 +1,108 @@ +>Active Region", ...], + * "event_visibility_selections": { "HEK": {"marker_visibility":true, + * "label_visibility":false}, ... } + * } + * + * EventsStateManager is the one-shot adapter: it already knows how to walk the + * legacy tree and emit canonical selection paths. An empty/absent tree yields + * empty selections and all-true visibility, so the same path covers the rows + * whose blob is {} (no events were ever selected). + * + * Included by the three management/events/migrate_*_events_shape.php runners; + * all four files retire in the post-deploy cleanup alongside EventsStateManager. + * + * @category Migration + * @package Helioviewer + */ + +use Helioviewer\Api\Event\EventsStateManager; +use Helioviewer\Api\Event\Api\EventsApi; +use Helioviewer\Api\Sentry\Sentry; + +// EventsStateManager::getSelections() reports unmapped event pins to Sentry. +// These CLI migrations run outside the web bootstrap that normally initializes +// it, so ensure a (disabled, VoidClient) instance exists — an empty config +// defaults to disabled — otherwise those reports throw. No-op if the caller +// already initialized Sentry. +if (Sentry::$client === null) { + Sentry::init([]); +} + +/** + * @param array $tree Legacy events tree (tree_HEK / tree_CCMC / ...), or []. + * @return array{event_selections: string[], event_visibility_selections: array} + */ +function events_shape_from_tree(array $tree): array +{ + // Canonical selection paths — the manager does the legacy-tree walk. + $selections = EventsStateManager::buildFromEventsState($tree)->getSelections(); + + // Per-source visibility. The legacy tree stores markers_visible / + // labels_visible per tree_SOURCE; a missing flag means "on" by historical + // convention (matches the manager's own default). + $visibility = []; + foreach (EventsApi::VALID_SOURCES as $source) { + $group = $tree['tree_' . $source] ?? []; + $visibility[$source] = [ + 'marker_visibility' => (bool)($group['markers_visible'] ?? true), + 'label_visibility' => (bool)($group['labels_visible'] ?? true), + ]; + } + + return [ + 'event_selections' => $selections, + 'event_visibility_selections' => $visibility, + ]; +} + +/** + * Accumulate a conversion into $bucket keyed by its unique signature, so many + * rows that share the same "tree => shape" conversion collapse into a single + * listed entry (with a count and a sample id). $bucket is passed by reference. + * + * @param array $bucket accumulator, keyed by conversion signature + * @param string $sampleId a human label for one row with this conversion + * @param array $tree the legacy input tree (or [] when the row had none) + * @param array $shape the derived new-shape blob + */ +function events_migration_collect(array &$bucket, string $sampleId, array $tree, array $shape): void +{ + $sig = json_encode([$tree, $shape]); + if (!isset($bucket[$sig])) { + $bucket[$sig] = ['count' => 0, 'sample' => $sampleId, 'tree' => $tree, 'shape' => $shape]; + } + $bucket[$sig]['count']++; +} + +/** + * Print each UNIQUE conversion once — "tree => event_selections & + * event_visibility_selections" — separated by a banner line so they are easy to + * scan. Identical conversions are folded together with a row count. + * + * @param array $bucket the accumulator filled by events_migration_collect() + * @param string $table table name, for the per-entry heading + */ +function events_migration_print_unique(array $bucket, string $table): void +{ + $json = JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE; + $sep = str_repeat('*', 60); + + echo $sep . "\n"; + foreach ($bucket as $entry) { + echo "{$table}: {$entry['count']} row(s), e.g. {$entry['sample']}\n"; + echo " tree => " . ($entry['tree'] === [] ? "{} (no events)" : json_encode($entry['tree'], $json)) . "\n"; + echo " event_selections => " . json_encode($entry['shape']['event_selections'], $json) . "\n"; + echo " event_visibility_selections => " . json_encode($entry['shape']['event_visibility_selections'], $json) . "\n"; + echo $sep . "\n"; + } + echo count($bucket) . " unique conversion(s)\n"; +} diff --git a/management/events/migrate_client_states_events_shape.php b/management/events/migrate_client_states_events_shape.php new file mode 100644 index 000000000..d07faf23b --- /dev/null +++ b/management/events/migrate_client_states_events_shape.php @@ -0,0 +1,72 @@ +) resolve against it, so the id MUST stay + * byte-identical. This uses ClientState::update() (UPDATE at a fixed id), + * never upsert() (which re-hashes and would orphan every existing URL). + * Post-deploy saves still go through upsert(), correctly hashing new-shape JSON. + * + * - DRY-RUN BY DEFAULT. It only writes when passed --apply. Either way it + * prints "eventLayers => event_selections & event_visibility_selections" + * for every row it would migrate, so the mapping can be validated first. + * - Idempotent + resumable: rows already carrying event_selections are skipped. + * - Runs inside the maintenance window, after the new code + schema are deployed. + * + * Retired in the post-deploy cleanup (with EventsStateManager). + * + * Usage: + * php management/events/migrate_client_states_events_shape.php # dry-run + * php management/events/migrate_client_states_events_shape.php --apply # write + */ + +require_once sprintf('%s/../../vendor/autoload.php', __DIR__); +require_once sprintf('%s/../config.php', __DIR__); +require_once sprintf('%s/../../src/Database/ClientState.php', __DIR__); +require_once sprintf('%s/events_shape.php', __DIR__); + +$apply = in_array('--apply', $argv, true); +echo $apply + ? "MODE: APPLY — writing changes to client_states\n\n" + : "MODE: DRY-RUN — no writes; re-run with --apply to write\n\n"; + +$client_state = new ClientState(); +$rows = $client_state->all(1000000); + +$migrated = 0; +$skipped = 0; +$conversions = []; +foreach ($rows as $row) { + $id = $row['id']; // SHA-256 hex — MUST stay the same + $state = json_decode($row['state'], true) ?? []; + + // Already new-shape — leave it alone (idempotency / resume). + if (isset($state['event_selections'])) { + $skipped++; + continue; + } + + $tree = (isset($state['eventLayers']) && is_array($state['eventLayers'])) + ? $state['eventLayers'] + : []; + $shape = events_shape_from_tree($tree); + events_migration_collect($conversions, $id, $tree, $shape); + + $state['event_selections'] = $shape['event_selections']; + $state['event_visibility_selections'] = $shape['event_visibility_selections']; + unset($state['eventLayers']); // deployed code + schema no longer carry it + + if ($apply) { + // UPDATE at the fixed id — preserves the shared-URL hash. + $client_state->update($id, $state); + } + $migrated++; +} + +events_migration_print_unique($conversions, 'client_states'); + +$verb = $apply ? "migrated" : "would migrate"; +echo "client_states: $verb $migrated, skipped $skipped (already new-shape)\n"; diff --git a/management/events/migrate_movies_events_shape.php b/management/events/migrate_movies_events_shape.php new file mode 100644 index 000000000..cc0596f23 --- /dev/null +++ b/management/events/migrate_movies_events_shape.php @@ -0,0 +1,68 @@ + event_selections & event_visibility_selections" for every + * row it would migrate, so the mapping can be validated before committing. + * - Idempotent + resumable: rows already carrying event_selections are skipped. + * - The primary key (auto-inc id) is never touched. + * - Runs inside the maintenance window, after the new code is deployed. + * + * Retired in the post-deploy cleanup (with EventsStateManager). + * + * Usage: + * php management/events/migrate_movies_events_shape.php # dry-run + * php management/events/migrate_movies_events_shape.php --apply # write + */ + +require_once sprintf('%s/../../vendor/autoload.php', __DIR__); +require_once sprintf('%s/../config.php', __DIR__); +require_once sprintf('%s/../../src/Database/DbConnection.php', __DIR__); +require_once sprintf('%s/events_shape.php', __DIR__); + +$apply = in_array('--apply', $argv, true); +echo $apply + ? "MODE: APPLY — writing changes to movies\n\n" + : "MODE: DRY-RUN — no writes; re-run with --apply to write\n\n"; + +$db = new Database_DbConnection(); +$res = $db->query("SELECT id, eventsState FROM movies"); + +$migrated = 0; +$skipped = 0; +$conversions = []; +while ($row = $res->fetch_assoc()) { + $tree = json_decode($row['eventsState'] ?? '', true); + if (!is_array($tree)) { + $tree = []; + } + + // Already new-shape — leave it alone (idempotency / resume). + if (isset($tree['event_selections'])) { + $skipped++; + continue; + } + + $shape = events_shape_from_tree($tree); + events_migration_collect($conversions, "#{$row['id']}", $tree, $shape); + + if ($apply) { + $new_blob = json_encode($shape); + $stmt = $db->link->prepare("UPDATE movies SET eventsState = ? WHERE id = ?"); + $stmt->bind_param('si', $new_blob, $row['id']); + $stmt->execute(); + $stmt->close(); + } + $migrated++; +} +$res->close(); + +events_migration_print_unique($conversions, 'movies'); + +$verb = $apply ? "migrated" : "would migrate"; +echo "movies: $verb $migrated, skipped $skipped (already new-shape)\n"; diff --git a/management/events/migrate_screenshots_events_shape.php b/management/events/migrate_screenshots_events_shape.php new file mode 100644 index 000000000..31810c529 --- /dev/null +++ b/management/events/migrate_screenshots_events_shape.php @@ -0,0 +1,67 @@ + event_selections & event_visibility_selections" for every + * row it would migrate, so the mapping can be validated before committing. + * - Idempotent + resumable: rows already carrying event_selections are + * skipped, so the script is safe to re-run and to interrupt. + * - The primary key (auto-inc id) is never touched. + * - Runs inside the maintenance window, after the new code is deployed. + * + * Retired in the post-deploy cleanup (with EventsStateManager). + * + * Usage: + * php management/events/migrate_screenshots_events_shape.php # dry-run + * php management/events/migrate_screenshots_events_shape.php --apply # write + */ + +require_once sprintf('%s/../../vendor/autoload.php', __DIR__); +require_once sprintf('%s/../config.php', __DIR__); +require_once sprintf('%s/../../src/Database/DbConnection.php', __DIR__); +require_once sprintf('%s/events_shape.php', __DIR__); + +$apply = in_array('--apply', $argv, true); +echo $apply + ? "MODE: APPLY — writing changes to screenshots\n\n" + : "MODE: DRY-RUN — no writes; re-run with --apply to write\n\n"; + +$db = new Database_DbConnection(); +$res = $db->query("SELECT id, eventsState FROM screenshots"); + +$migrated = 0; +$skipped = 0; +$conversions = []; +while ($row = $res->fetch_assoc()) { + $tree = json_decode($row['eventsState'] ?? '', true); + if (!is_array($tree)) { + $tree = []; + } + + // Already new-shape — leave it alone (idempotency / resume). + if (isset($tree['event_selections'])) { + $skipped++; + continue; + } + + $shape = events_shape_from_tree($tree); + events_migration_collect($conversions, "#{$row['id']}", $tree, $shape); + + if ($apply) { + $new_blob = json_encode($shape); + $stmt = $db->link->prepare("UPDATE screenshots SET eventsState = ? WHERE id = ?"); + $stmt->bind_param('si', $new_blob, $row['id']); + $stmt->execute(); + $stmt->close(); + } + $migrated++; +} +$res->close(); + +events_migration_print_unique($conversions, 'screenshots'); + +$verb = $apply ? "migrated" : "would migrate"; +echo "screenshots: $verb $migrated, skipped $skipped (already new-shape)\n"; diff --git a/settings/Config.Example.ini b/settings/Config.Example.ini index 4958a5af6..7fdc85292 100644 --- a/settings/Config.Example.ini +++ b/settings/Config.Example.ini @@ -86,15 +86,19 @@ db_events = true import_events_auth = "" ; This is the URL of the eventsapi, you can set to your development one if needed -events_api_url = "https://events.helioviewer.org" +events_api_url = "https://events.necdet.helioviewer.org" -; Timeout in seconds for Events API requests -events_api_timeout = 10 +; Timeout in seconds for Events API requests. Must comfortably exceed one +; chunk's time: at ~165ms/timestamp a 150-timestamp chunk is ~25s, and the +; events server's cold/first request can spike higher, so keep generous margin. +; If a chunk exceeds this, curl aborts (28) and EventContext::build swallows it +; into an empty context -> movie renders with no events. +events_api_timeout = 90 ; Number of timestamps per Events API batch request when building a movie. -; Smaller = faster individual requests, more requests total; larger = fewer -; round-trips but slower per request. 50 is a balanced default. -events_api_events_per_frame_chunksize = 50 +; Larger = fewer round-trips per movie, but each chunk must finish within +; events_api_timeout. Capped by events_api_events_per_frame_max_chunk_size below. +events_api_events_per_frame_chunksize = 150 ; Upstream-imposed cap on timestamps per Events API batch request. ; Any chunk size larger than this gets clamped down to this value. diff --git a/src/Actions.php b/src/Actions.php index dd30f2835..b60a99b79 100644 --- a/src/Actions.php +++ b/src/Actions.php @@ -12,6 +12,7 @@ 'getUsageStatistics' => 'WebClient', 'getDataCoverageTimeline' => 'WebClient', 'getDataCoverage' => 'WebClient', + 'eventsDataCoverage' => 'WebClient', 'updateDataCoverage' => 'WebClient', // Deprecated, remove in V3, replaced by management scripts 'shortenURL' => 'WebClient', 'goto' => 'WebClient', diff --git a/src/Database/Statistics.php b/src/Database/Statistics.php index a105dad6b..cdb435ac2 100644 --- a/src/Database/Statistics.php +++ b/src/Database/Statistics.php @@ -791,6 +791,7 @@ private function _createCountsArray(){ 'getUsageStatistics' => array(), 'getDataCoverageTimeline' => array(), 'getDataCoverage' => array(), + 'eventsDataCoverage' => array(), 'updateDataCoverage' => array(), 'shortenURL' => array(), 'saveWebClientState' => array(), @@ -862,6 +863,7 @@ private function _createSummaryArray(){ 'getUsageStatistics' => 0, 'getDataCoverageTimeline' => 0, 'getDataCoverage' => 0, + 'eventsDataCoverage' => 0, 'updateDataCoverage' => 0, 'shortenURL' => 0, 'saveWebClientState' => 0, diff --git a/src/Event/Api/EventsApi.php b/src/Event/Api/EventsApi.php index 0e7907c82..6ed5d98f7 100644 --- a/src/Event/Api/EventsApi.php +++ b/src/Event/Api/EventsApi.php @@ -12,16 +12,16 @@ * EventsApi Client * * HTTP client for the Helioviewer Events API service. - * Handles fetching solar events (HEK, CCMC, RHESSI) with coordinate rotation, - * batch observations for movie frames, event distributions for timelines, - * and event range queries. + * Handles fetching solar events (HEK, CCMC, RHESSI, WSA) with coordinate + * rotation, batched observations with selection filtering for movie frames, + * event distributions for timelines, and event range queries. * * All methods capture errors to Sentry and throw EventsApiException on failure. */ class EventsApi implements EventsApiInterface { /** Known event sources */ - public const VALID_SOURCES = ['HEK', 'CCMC', 'RHESSI']; + public const VALID_SOURCES = ['HEK', 'CCMC', 'RHESSI', 'WSA']; /** Fallback used when the HV_* config constant is not defined. */ private const DEFAULT_MAX_CHUNK_SIZE = 150; @@ -51,18 +51,6 @@ public static function maxSelections(): int private ClientInterface $client; private SentryClientInterface $sentry; - private LegacyEventsInterface $legacyEvents; - - /** - * Filter an array of source names to only valid ones. - * - * @param string[] $sources - * @return string[] Only sources that exist in VALID_SOURCES - */ - public static function filterSources(array $sources): array - { - return array_values(array_intersect($sources, self::VALID_SOURCES)); - } /** * EventsApi constructor. @@ -71,9 +59,8 @@ public static function filterSources(array $sources): array * * @param ClientInterface|null $client Optional Guzzle client for testing * @param SentryClientInterface|null $sentry Optional Sentry client for testing - * @param LegacyEventsInterface|null $legacyEvents Optional converter for testing */ - public function __construct(ClientInterface $client = null, SentryClientInterface $sentry = null, LegacyEventsInterface $legacyEvents = null) + public function __construct(ClientInterface $client = null, SentryClientInterface $sentry = null) { $timeout = defined('HV_EVENTS_API_TIMEOUT') ? HV_EVENTS_API_TIMEOUT : 10; $connectTimeout = 2; @@ -94,7 +81,6 @@ public function __construct(ClientInterface $client = null, SentryClientInterfac $this->client = $client ?? new Client($options); $this->sentry = $sentry ?? Sentry::$client; - $this->legacyEvents = $legacyEvents ?? new LegacyEvents(); $this->sentry->setContext('EventsApi', [ 'api_url' => $baseUrl, @@ -206,78 +192,6 @@ public function getDistributions(string $size, int $fromTimestamp, int $toTimest } } - /** {@inheritdoc} */ - public function getEventsBatch(array $timestamps, array $sources, int $chunkSize = 50, string $logLabel = ''): array - { - // Only allow known sources - $validSources = self::filterSources($sources); - if (empty($validSources)) { - throw new EventsApiException("No valid sources given. Valid sources: " . implode(', ', self::VALID_SOURCES)); - } - if (empty($timestamps)) { - return []; - } - if ($chunkSize < 1) { - $chunkSize = defined('HV_EVENTS_API_EVENTS_PER_FRAME_CHUNKSIZE') ? (int) HV_EVENTS_API_EVENTS_PER_FRAME_CHUNKSIZE : 50; - } - $maxChunk = self::maxChunkSize(); - if ($chunkSize > $maxChunk) { - $chunkSize = $maxChunk; - } - - $sourcesParam = implode('::', $validSources); - $chunks = array_chunk($timestamps, $chunkSize); - $url = "/helioviewer/events/{$sourcesParam}/observations"; - - // Closure to fetch a single chunk of timestamps - $fetchChunk = function (array $chunkTimestamps) use ($url) { - $this->sentry->setContext('EventsApi', [ - 'endpoint' => $url, - 'timestamp_count' => count($chunkTimestamps), - ]); - - try { - $response = $this->client->request('POST', $url, [ - 'json' => ['timestamps' => $chunkTimestamps] - ]); - return $this->parseResponse($response); - } catch (\Throwable $e) { - $this->sentry->setContext('EventsApi', [ - 'error' => $e->getMessage(), - ]); - $exception = new EventsApiException("Failed to fetch batch events: " . $e->getMessage(), 0, $e); - $this->sentry->capture($exception); - throw $exception; - } - }; - - $logChunk = function (int $i, int $total, int $size, int $elapsedMs) use ($logLabel) { - if ($logLabel === '') { - return; - } - error_log(sprintf( - "[%s] EventsApi chunk %d/%d (%d timestamps) took %dms", - $logLabel, $i + 1, $total, $size, $elapsedMs - )); - }; - - // First chunk returns full response (event_types + events + observations) - $start = microtime(true); - $merged = $fetchChunk($chunks[0]); - $logChunk(0, count($chunks), count($chunks[0]), (int) round((microtime(true) - $start) * 1000)); - - // Subsequent chunks only add new observations (event_types and events are the same) - for ($i = 1; $i < count($chunks); $i++) { - $start = microtime(true); - $chunk = $fetchChunk($chunks[$i]); - $logChunk($i, count($chunks), count($chunks[$i]), (int) round((microtime(true) - $start) * 1000)); - $merged['observations'] += $chunk['observations']; - } - - // Convert deduplicated response to legacy format per timestamp - return $this->legacyEvents->convertAll($merged); - } - /** {@inheritdoc} */ public function getEventsForFramesWithSelections( array $timestamps, @@ -303,7 +217,10 @@ public function getEventsForFramesWithSelections( $chunkSize = $maxChunk; } - $url = "/helioviewer/events/frames_with_selections"; + // ?withDelta asks the upstream to include the per-observation rotation + // deltas (dx, dy) in the 'timestamps' block, so EventContext can shift + // each event's marker + footprint to the frame's timestamp. + $url = "/helioviewer/events/frames_with_selections?withDelta"; $chunks = array_chunk($timestamps, $chunkSize); $fetchChunk = function (array $chunkTimestamps) use ($url, $selections) { diff --git a/src/Event/Api/EventsApiInterface.php b/src/Event/Api/EventsApiInterface.php index b3c98f4c0..f750cca02 100644 --- a/src/Event/Api/EventsApiInterface.php +++ b/src/Event/Api/EventsApiInterface.php @@ -50,19 +50,6 @@ public function getEventsInRange(int $fromTimestamp, int $toTimestamp, array $pa */ public function getDistributions(string $size, int $fromTimestamp, int $toTimestamp, array $paths): array; - /** - * Fetch events for multiple observation timestamps in batched requests. - * Returns legacy format keyed by timestamp. - * - * @param string[] $timestamps Array of observation datetime strings - * @param string[] $sources Array of source names (e.g. ['HEK', 'CCMC', 'RHESSI']) - * @param int $chunkSize Max timestamps per upstream POST request - * @param string $logLabel Optional label prepended to per-chunk error_log lines (e.g. "Movie:Xp66n") - * @return array Keyed by timestamp, each value is legacy-format event categories - * @throws EventsApiException on API errors or unexpected responses - */ - public function getEventsBatch(array $timestamps, array $sources, int $chunkSize = 50, string $logLabel = ''): array; - /** * Fetch events for multiple observation timestamps filtered by a list of * path-prefix selections. Posts to /helioviewer/events/frames_with_selections. @@ -70,7 +57,7 @@ public function getEventsBatch(array $timestamps, array $sources, int $chunkSize * Returns the RAW merged response (no legacy conversion): * [ * 'events' => [ => {path, label, start, end, hv_hpc_x, hv_hpc_y, footprint, type, pin} ], - * 'timestamps' => [ => { => {hv_hpc_x, hv_hpc_y} } ], + * 'timestamps' => [ => { => {dx, dy} } ], * ] * * Timestamps are paginated by $chunkSize (capped at the upstream limit of diff --git a/src/Event/Api/LegacyEvents.php b/src/Event/Api/LegacyEvents.php deleted file mode 100644 index c845060ba..000000000 --- a/src/Event/Api/LegacyEvents.php +++ /dev/null @@ -1,96 +0,0 @@ - $obs) { - $result[$timestamp] = $this->convert($eventTypes, $events, $obs); - } - - return $result; - } - - /** - * Convert one timestamp's batch data to legacy event_categories format. - * Merges static event data with per-timestamp rotated coordinates, - * shifts footprint polygons by the rotation delta, - * and rebuilds the category/group/data hierarchy. - * - * @param array $eventTypes Category/group structure with event_ids references - * @param array $events Static event data keyed by event ID - * @param array $obs Rotated coordinates keyed by event ID for this timestamp - * @return array Legacy format: [{pin, name, groups: [{name, data: [...]}]}] - */ - public function convert(array $eventTypes, array $events, array $obs): array - { - $categories = []; - - foreach ($eventTypes as $et) { - $groups = []; - - foreach ($et['groups'] as $group) { - $data = []; - - foreach ($group['event_ids'] as $eventId) { - if (!isset($obs[$eventId])) continue; - - $event = $events[$eventId] ?? null; - if (!$event) continue; - - $coords = $obs[$eventId]; - - $legacyEvent = $event; - $legacyEvent['id'] = $eventId; - $legacyEvent['hv_hpc_x'] = $coords['hv_hpc_x']; - $legacyEvent['hv_hpc_y'] = $coords['hv_hpc_y']; - $legacyEvent['hv_hpc_x_final'] = $coords['hv_hpc_x']; - $legacyEvent['hv_hpc_y_final'] = $coords['hv_hpc_y']; - - $dx = $coords['hv_hpc_x'] - $event['hv_hpc_x']; - $dy = $coords['hv_hpc_y'] - $event['hv_hpc_y']; - if (!empty($event['footprint'])) { - $legacyEvent['footprint'] = array_map( - fn($p) => ['x' => $p['x'] + $dx, 'y' => $p['y'] + $dy], - $event['footprint'] - ); - } - - $data[] = $legacyEvent; - } - - if (!empty($data)) { - $groups[] = ['name' => $group['name'], 'data' => $data]; - } - } - - if (!empty($groups)) { - $categories[] = [ - 'pin' => $et['pin'], - 'name' => $et['name'], - 'groups' => $groups - ]; - } - } - - return $categories; - } -} diff --git a/src/Event/Api/LegacyEventsInterface.php b/src/Event/Api/LegacyEventsInterface.php deleted file mode 100644 index 7c439f737..000000000 --- a/src/Event/Api/LegacyEventsInterface.php +++ /dev/null @@ -1,27 +0,0 @@ - '019c3d8f-...', * 'label' => 'AR 13700', // empty string '' when labels are hidden for this source @@ -22,7 +29,7 @@ * 'pin' => 'AR', * 'hv_hpc_x' => -119.0, // rotated for this frame * 'hv_hpc_y' => 570.2, - * 'footprint' => [{x,y}, ...], // already shifted by (dx,dy) + * 'footprint' => [[{x,y}, ...], ...], // list of rings; every point already shifted by (dx,dy) * ] * * NOTE: there is no separate label_visibility flag. The renderer treats an @@ -34,14 +41,24 @@ class EventContext private static ?self $emptyInstance = null; /** - * @param array>> $eventsByDate - * date => list of event dicts. - * Invariant: every timestamp passed to build() appears as a key here, - * even if its list is empty. We rely on this to detect the - * "caller asks for an unrequested date" programming-bug case. + * @param array $requestedTimestamps Set of timestamps passed to build(), + * used to distinguish "no events at this + * frame" (expected) from "caller asked + * for a date we never fetched" (bug). + * @param array> $events Raw upstream 'events' block: uuid => event data. + * @param array> $observations + * Raw upstream 'timestamps' block: ts => uuid => {dx, dy}. + * @param array $visibilitySelections Per-source visibility flags (label_visibility only, + * marker_visibility is filtered at build() time). */ - private function __construct(private array $eventsByDate) - { + private function __construct( + private array $requestedTimestamps = [], + private array $events = [], + private array $observations = [], + private array $visibilitySelections = [], + private array $rawSelections = [], + private array $rawVisibilitySelections = [] + ) { } /** @@ -51,16 +68,16 @@ private function __construct(private array $eventsByDate) */ public static function empty(): self { - return self::$emptyInstance ??= new self([]); + return self::$emptyInstance ??= new self(); } /** - * Build the context by fetching events for $timestamps filtered by $selections. + * Build the context by fetching events for $frameTimestamps filtered by $selections. * - * Empty $timestamps OR empty $selections -> no HTTP call, empty context. + * Empty $frameTimestamps OR empty $selections -> no HTTP call, empty context. * HTTP failure -> Sentry capture, returns an empty context. * - * @param string[] $timestamps dates to fetch events for + * @param string[] $frameTimestamps dates (one per movie/screenshot frame) to fetch events for * @param string[] $selections path-prefix selections (from EventsStateManager::getSelections()) * @param array $visibilitySelections per-source visibility map (from EventsStateManager::getVisibilitySelections()) * @param EventsApiInterface $api @@ -68,132 +85,180 @@ public static function empty(): self * @param string $logLabel forwarded to the API client (per-chunk error_log tag) */ public static function build( - array $timestamps, + array $frameTimestamps, array $selections, array $visibilitySelections, EventsApiInterface $api, int $chunkSize = 50, string $logLabel = '' ): self { - // Short-circuit when there's nothing to fetch. Pre-populate with empty - // lists per requested timestamp so the post-build invariant holds: - // every requested date appears as a key in $eventsByDate. - if (empty($timestamps) || empty($selections)) { - return new self(array_fill_keys($timestamps, [])); + // Remember what the client asked for before the marker_visibility filter + // below mutates $selections. This is the blob we persist so a later + // reTakeScreenshot / movie reQueue reproduces the identical render. + $rawSelections = $selections; + $rawVisibilitySelections = $visibilitySelections; + + // For each source whose marker_visibility is explicitly false, drop + // its "SOURCE>>..." selections. Missing / non-false → assume visible. + foreach ($visibilitySelections as $source => $flags) { + if (($flags['marker_visibility'] ?? true) === false) { + $selections = array_values(array_filter( + $selections, + fn(string $p) => !str_starts_with($p, $source . '>>') + )); + } + } + + $requestedTimestampsSet = array_fill_keys($frameTimestamps, true); + + // Short-circuit when there's nothing to fetch. requestedTimestamps still + // remembers the caller's set so getEventsForDate() returns [] for known + // dates without triggering the "unrequested date" Sentry signal. + if (empty($frameTimestamps) || empty($selections)) { + return new self( + $requestedTimestampsSet, + rawSelections: $rawSelections, + rawVisibilitySelections: $rawVisibilitySelections + ); } try { $raw = $api->getEventsForFramesWithSelections( - $timestamps, $selections, $chunkSize, $logLabel + $frameTimestamps, $selections, $chunkSize, $logLabel ); } catch (\Throwable $e) { Sentry::setContext('EventContext', [ - 'timestamps_count' => count($timestamps), - 'selections' => $selections, - 'log_label' => $logLabel, + 'frame_timestamps_count' => count($frameTimestamps), + 'selections' => $selections, + 'log_label' => $logLabel, ]); Sentry::capture($e); - return new self(array_fill_keys($timestamps, [])); + return new self( + $requestedTimestampsSet, + rawSelections: $rawSelections, + rawVisibilitySelections: $rawVisibilitySelections + ); } - // Shape the raw frames_with_selections response into per-date - // draw-ready arrays. Footprints get rotation-shifted by (dx,dy). - // For hidden-label sources we set 'label' to '' so the renderer - // (which already treats empty label as "skip label drawing") needs - // no extra logic. - $events = $raw['events'] ?? []; - $observations = $raw['timestamps'] ?? []; - $eventsByDate = []; - - foreach ($observations as $ts => $obs) { - $list = []; - foreach ($obs as $eventId => $coords) { - $event = $events[$eventId] ?? null; - if (!$event) { - continue; - } - - // Determine source by parsing the event's canonical path. - // path is e.g. "HEK>>Active Region>>SPoCA" - $path = $event['path'] ?? ''; - $source = explode('>>', $path)[0] ?? ''; - // Default to true: when the source isn't in the visibility map, - // assume labels are on (matches getVisibilitySelections()'s default). - $labelVisible = (bool) ($visibilitySelections[$source]['label_visibility'] ?? true); - - // Rotation delta: how much did this frame's rotated coords - // drift from the event's "canonical" coords? - $dx = $coords['hv_hpc_x'] - ($event['hv_hpc_x'] ?? 0.0); - $dy = $coords['hv_hpc_y'] - ($event['hv_hpc_y'] ?? 0.0); - - $footprint = []; - if (!empty($event['footprint'])) { - $footprint = array_map( - fn($p) => ['x' => $p['x'] + $dx, 'y' => $p['y'] + $dy], - $event['footprint'] - ); - } - - $type = $event['type'] ?? 'UNK'; - $list[] = [ - 'id' => $eventId, - // Empty label = "do not draw a label". This is how we - // encode "labels hidden for this source" downstream. - 'label' => $labelVisible ? ($event['label'] ?? '') : '', - 'type' => $type, - 'pin' => $event['pin'] ?? $type, - 'hv_hpc_x' => $coords['hv_hpc_x'], - 'hv_hpc_y' => $coords['hv_hpc_y'], - 'footprint' => $footprint, - ]; - } - $eventsByDate[$ts] = $list; + // Wrap each raw event once so getEventsForDate can call methods on it + // instead of poking at array keys. Cheap: N events, not N × frames. + $events = []; + foreach ($raw['events'] ?? [] as $uuid => $data) { + $events[$uuid] = new EventRecord($data); } - return new self($eventsByDate); + // Stash the raw blocks verbatim. Shaping happens lazily in getEventsForDate. + return new self( + $requestedTimestampsSet, + $events, + $raw['timestamps'] ?? [], + $visibilitySelections, + $rawSelections, + $rawVisibilitySelections + ); } /** * Returns the draw-ready event list for $date, or [] if none. * - * The upstream guarantees that every timestamp passed to build() ends up - * as a key in the response (even when its list is empty), so a missing - * key here when the context has some dates means the caller is asking - * for a date that was never part of the build() request. That's a - * programming bug; we Sentry-log and return [] without blowing up the - * render. + * Computes on demand: every call walks the observations for $date and + * builds fresh event dicts (with rotation-shifted footprints). Nothing is + * cached across calls, so live memory stays bounded to one frame. * - * If $this->eventsByDate is itself empty (e.g. the EventContext::empty() - * singleton, or a build() that short-circuited), the "missing key" case - * is expected — no Sentry signal. + * Invariant: every timestamp passed to build() is remembered in + * $requestedTimestamps. If the caller asks for a date that was NOT part of + * that set (and the context isn't the empty singleton), that's a + * programming bug -- we Sentry-log and return [] without blowing up render. */ public function getEventsForDate(string $date): array { - if (!array_key_exists($date, $this->eventsByDate)) { - if (!empty($this->eventsByDate)) { + if (!isset($this->requestedTimestamps[$date])) { + if (!empty($this->requestedTimestamps)) { Sentry::setContext('EventContext', [ 'requested_date' => $date, - 'available_dates' => array_keys($this->eventsByDate), - 'events_by_date' => $this->eventsByDate, + 'available_dates' => array_keys($this->requestedTimestamps), ]); Sentry::message("EventContext::getEventsForDate called with a date that wasn't part of build()"); } return []; } - return $this->eventsByDate[$date]; + + $obs = $this->observations[$date] ?? []; + if (empty($obs) || empty($this->events)) { + return []; + } + + $list = []; + foreach ($obs as $eventId => $coords) { + $event = $this->events[$eventId] ?? null; + if (!$event) { + continue; + } + + // Default to true: when the source isn't in the visibility map, + // assume labels are on. + $source = $event->getSourceFromPath(); + $labelVisible = (bool) ($this->visibilitySelections[$source]['label_visibility'] ?? true); + + // Rotation delta from canonical to this frame — now delivered + // directly by the upstream events API. + $dx = $coords['dx'] ?? 0.0; + $dy = $coords['dy'] ?? 0.0; + + $footprint = []; + $rawFootprint = $event->get('footprint'); + if (!empty($rawFootprint)) { + $footprint = array_map( + fn(array $ring) => array_map( + fn($p) => ['x' => $p['x'] + $dx, 'y' => $p['y'] + $dy], + $ring + ), + $rawFootprint + ); + } + + $type = $event->get('type', 'UNK'); + $list[] = [ + 'id' => $eventId, + 'label' => $labelVisible ? $event->get('label', '') : '', + 'type' => $type, + 'pin' => $event->get('pin', $type), + 'hv_hpc_x' => $event->get('hv_hpc_x', 0.0) + $dx, + 'hv_hpc_y' => $event->get('hv_hpc_y', 0.0) + $dy, + 'footprint' => $footprint, + ]; + } + return $list; } /** - * Whether any timestamp produced at least one event. Convenience for - * callers that want to short-circuit downstream work. + * Whether any timestamp had at least one observation referencing a known + * event. Cheap: doesn't materialize any footprints. */ public function hasEvents(): bool { - foreach ($this->eventsByDate as $list) { - if (!empty($list)) { + if (empty($this->events)) { + return false; + } + foreach ($this->observations as $obs) { + if (!empty($obs)) { return true; } } return false; } + + /** + * The persist blob: the raw event_selections + event_visibility_selections + * that produced this context, exactly as the client sent them (before the + * marker_visibility filter). Written to the screenshots/movies row so a + * cache-miss retake or reQueue rebuilds the same render. + */ + public function exportEventsStateBlob(): string + { + return json_encode([ + 'event_selections' => $this->rawSelections, + 'event_visibility_selections' => $this->rawVisibilitySelections, + ]); + } } diff --git a/src/Event/EventRecord.php b/src/Event/EventRecord.php new file mode 100644 index 000000000..96674be33 --- /dev/null +++ b/src/Event/EventRecord.php @@ -0,0 +1,35 @@ +>Active Region>>SPoCA" -> "HEK". Missing / empty path -> ''. + */ + public function getSourceFromPath(): string + { + return explode('>>', $this->data['path'] ?? '', 2)[0]; + } + + /** + * Generic accessor for raw fields. Returns $default when the key is missing. + */ + public function get(string $key, $default = null) + { + return $this->data[$key] ?? $default; + } +} diff --git a/src/Event/EventSelections.php b/src/Event/EventSelections.php deleted file mode 100644 index abbf17753..000000000 --- a/src/Event/EventSelections.php +++ /dev/null @@ -1,182 +0,0 @@ - - * @license http://www.mozilla.org/MPL/MPL-1.1.html Mozilla Public License 1.1 - * @link https://github.com/Helioviewer-Project - */ - -namespace Helioviewer\Api\Event; - -use ArrayAccess; -use Countable; -use IteratorAggregate; -use ArrayIterator; -use Traversable; - -class EventSelections implements ArrayAccess, Countable, IteratorAggregate -{ - public static array $event_types_map = [ - 'HEK' => [ - 'AR' => 'Active Region', - 'CE' => 'CME', - 'CH' => 'Coronal Hole', - 'EF' => 'Emerging Flux', - 'FI' => 'Filament', - 'FL' => 'Flare', - 'SG' => 'Sigmoid', - 'CC' => 'Coronal Cavity', - 'CD' => 'Coronal Dimming', - 'CJ' => 'Coronal Jet', - 'CR' => 'Coronal Rain', - 'CW' => 'Coronal Wave', - 'ER' => 'Eruption', - 'FA' => 'Filament Activation', - 'FE' => 'Filament Eruption', - 'LP' => 'Loop', - 'OS' => 'Oscillation', - 'PG' => 'Plage', - 'SP' => 'Spray Surge', - 'SS' => 'Sunspot', - 'OT' => 'Other', - 'NR' => 'Nothing Reported', - 'TO' => 'Topological Object', - 'HY' => 'Hypothesis', - 'BU' => 'UVBurst', - 'EE' => 'Explosive Event', - 'PB' => 'Prominence Bubble', - 'PT' => 'Peacock Tail', - 'EP' => 'SEPs', - 'IC' => 'ICMEs', - 'SR' => 'SIRs', - // 'UNK' => 'Unknown', // Not in events API - ], - 'CCMC' => [ - 'C3' => 'DONKI', - 'FP' => 'Solar Flare Predictions', - ], - 'RHESSI' => [ - 'F2' => 'Solar Flares', - ], - ]; - - private array $selections; - - /** - * Creates a new EventSelections - * @param array $selections Array of selection strings like 'HEK>>Active Region>>Spoca' - */ - private function __construct(array $selections) - { - $this->selections = $selections; - } - - /** - * Creates a new EventSelections from legacy event string - * @param string $events_state_string Legacy event string like "[AR,all,1],[FL,NOAA_SWPC,1]" - * @return EventSelections - */ - public static function buildFromLegacyEventStrings(string $events_state_string): EventSelections - { - $selections = []; - - // Prevent possible bugs - $events_state_string = trim($events_state_string); - - if (!empty($events_state_string)) { - $stripped = stripslashes($events_state_string); - // Remove only the outermost [ and ] - if (str_starts_with($stripped, '[') && str_ends_with($stripped, ']')) { - $stripped = substr($stripped, 1, -1); - } - $event_strings = explode("],[", $stripped); - - // Process individual events in string - foreach ($event_strings as $es) { - - $event_pieces = explode(",", $es); - - // there should be 3 elements - if (count($event_pieces) < 3) { - continue; - } - - list($event_type, $combined_frms, $visible) = $event_pieces; - - // Find the source (HEK, CCMC, RHESSI) and label for this event_type - $source = null; - $label = null; - foreach (self::$event_types_map as $src => $types) { - if (array_key_exists($event_type, $types)) { - $source = $src; - $label = $types[$event_type]; - break; - } - } - - // Skip if event_type not found in map - if ($source === null || $label === null) { - continue; - } - - $frms = explode(";", $combined_frms); - - // If 'all' or empty frms, just use SOURCE>>LABEL - if (empty($combined_frms) || $combined_frms === 'all' || in_array('all', $frms)) { - $selections[] = $source . '>>' . $label; - } else { - // For each specific FRM, create SOURCE>>LABEL>>FRM - foreach ($frms as $frm) { - $frm = trim($frm); - if (!empty($frm)) { - $selections[] = $source . '>>' . $label . '>>' . $frm; - } - } - } - } - } - - return new self($selections); - } - - // IteratorAggregate implementation - public function getIterator(): Traversable - { - return new ArrayIterator($this->selections); - } - - // Countable implementation - public function count(): int - { - return count($this->selections); - } - - // ArrayAccess implementation - public function offsetExists($offset): bool - { - return isset($this->selections[$offset]); - } - - public function offsetGet($offset): mixed - { - return $this->selections[$offset] ?? null; - } - - public function offsetSet($offset, $value): void - { - if (is_null($offset)) { - $this->selections[] = $value; - } else { - $this->selections[$offset] = $value; - } - } - - public function offsetUnset($offset): void - { - unset($this->selections[$offset]); - } -} diff --git a/src/Event/EventTree.php b/src/Event/EventTree.php index f1458409f..fdefdf717 100644 --- a/src/Event/EventTree.php +++ b/src/Event/EventTree.php @@ -8,7 +8,7 @@ /** * Buckets a flat list of events (the shape returned by * EventsApi::getEventsForSource()) into a "SOURCE>>Label" tree, using - * EventSelections::$event_types_map as the canonical catalogue. + * EventTypeCatalogue::MAP as the canonical catalogue. * * Usage: * $tree = EventTree::make($flatEvents, $requestedSources); @@ -46,10 +46,10 @@ public static function make(array $events, array $sources, ?SentryClientInterfac // Pre-seed every known bucket for the requested sources. foreach ($sources as $source) { - if (!isset(EventSelections::$event_types_map[$source])) { + if (!isset(EventTypeCatalogue::MAP[$source])) { continue; } - foreach (EventSelections::$event_types_map[$source] as $code => $label) { + foreach (EventTypeCatalogue::MAP[$source] as $code => $label) { $buckets[$source . '>>' . $label] = []; } } @@ -93,7 +93,7 @@ public static function make(array $events, array $sources, ?SentryClientInterfac 'requested_sources' => $sources, ]); $sentry->message( - 'simpletree: encountered paths not in EventSelections::$event_types_map' + 'simpletree: encountered paths not in EventTypeCatalogue::MAP' ); } diff --git a/src/Event/EventTypeCatalogue.php b/src/Event/EventTypeCatalogue.php new file mode 100644 index 000000000..4fb83a38b --- /dev/null +++ b/src/Event/EventTypeCatalogue.php @@ -0,0 +1,70 @@ + { event_type_code => human label } map for every + * event source Helioviewer understands. Single source of truth for turning a + * 2-letter event-type code into a canonical "SOURCE>>Label" path segment. + * + * Lifted verbatim from the former EventSelections::$event_types_map so the map + * survives that class's retirement. Consumed by EventTree (simpletree output) + * and LegacyEventsStringParser (URL bracket-string parsing). + * + * @category Event + * @package Helioviewer + * @license http://www.mozilla.org/MPL/MPL-1.1.html Mozilla Public License 1.1 + * @link https://github.com/Helioviewer-Project + */ + +namespace Helioviewer\Api\Event; + +final class EventTypeCatalogue +{ + public const MAP = [ + 'HEK' => [ + 'AR' => 'Active Region', + 'CE' => 'CME', + 'CH' => 'Coronal Hole', + 'EF' => 'Emerging Flux', + 'FI' => 'Filament', + 'FL' => 'Flare', + 'SG' => 'Sigmoid', + 'CC' => 'Coronal Cavity', + 'CD' => 'Coronal Dimming', + 'CJ' => 'Coronal Jet', + 'CR' => 'Coronal Rain', + 'CW' => 'Coronal Wave', + 'ER' => 'Eruption', + 'FA' => 'Filament Activation', + 'FE' => 'Filament Eruption', + 'LP' => 'Loop', + 'OS' => 'Oscillation', + 'PG' => 'Plage', + 'SP' => 'Spray Surge', + 'SS' => 'Sunspot', + 'OT' => 'Other', + 'NR' => 'Nothing Reported', + 'TO' => 'Topological Object', + 'HY' => 'Hypothesis', + 'BU' => 'UVBurst', + 'EE' => 'Explosive Event', + 'PB' => 'Prominence Bubble', + 'PT' => 'Peacock Tail', + 'EP' => 'SEPs', + 'IC' => 'ICMEs', + 'SR' => 'SIRs', + // 'UNK' => 'Unknown', // Not in events API + ], + 'CCMC' => [ + 'C3' => 'DONKI', + 'FP' => 'Solar Flare Predictions', + ], + 'RHESSI' => [ + 'F2' => 'Solar Flares', + ], + 'WSA' => [ + 'MC' => 'Magnetic Connectivity', + 'CH' => 'Coronal Hole', + ], + ]; +} diff --git a/src/Event/EventsStateManager.php b/src/Event/EventsStateManager.php index 249c64d51..3b575e70c 100644 --- a/src/Event/EventsStateManager.php +++ b/src/Event/EventsStateManager.php @@ -413,8 +413,8 @@ public function getSelections(): array // ('HEK', 'AR') -> 'Active Region' // ('HEK', 'FL') -> 'Flare' // ('CCMC', 'FP') -> 'Solar Flare Predictions' - // Unknown pin -> null -> skip (matches EventSelections behavior) - $label = EventSelections::$event_types_map[$source][$pin] ?? null; + // Unknown pin -> null -> skip + $label = EventTypeCatalogue::MAP[$source][$pin] ?? null; if ($label === null) { // Pin isn't in the map - usually means a typo or a new // event type we haven't registered yet. Visible signal, diff --git a/src/Event/LegacyEventsStringParser.php b/src/Event/LegacyEventsStringParser.php new file mode 100644 index 000000000..c8703d707 --- /dev/null +++ b/src/Event/LegacyEventsStringParser.php @@ -0,0 +1,133 @@ +>Label[>>FRM]" selection paths, resolving each + * event-type code against EventTypeCatalogue::MAP. + * + * Parsing logic lifted verbatim from the former + * EventSelections::buildFromLegacyEventStrings so it survives that class's + * retirement. The per-triple visibility flag (the trailing 1/0) is ignored, + * matching the original behavior -- every listed event is treated as selected. + * + * @category Event + * @package Helioviewer + * @license http://www.mozilla.org/MPL/MPL-1.1.html Mozilla Public License 1.1 + * @link https://github.com/Helioviewer-Project + */ + +namespace Helioviewer\Api\Event; + +final class LegacyEventsStringParser +{ + /** + * Parse a legacy bracket-string into canonical selection paths. + * + * @param string $events_state_string e.g. "[AR,all,1],[FL,NOAA_SWPC,1]" + * @return string[] canonical "SOURCE>>Label[>>FRM]" paths + */ + public static function parse(string $events_state_string): array + { + $selections = []; + + // Prevent possible bugs + $events_state_string = trim($events_state_string); + + if (!empty($events_state_string)) { + $stripped = stripslashes($events_state_string); + // Remove only the outermost [ and ] + if (str_starts_with($stripped, '[') && str_ends_with($stripped, ']')) { + $stripped = substr($stripped, 1, -1); + } + $event_strings = explode("],[", $stripped); + + // Process individual events in string + foreach ($event_strings as $es) { + + $event_pieces = explode(",", $es); + + // there should be 3 elements + if (count($event_pieces) < 3) { + continue; + } + + list($event_type, $combined_frms, $visible) = $event_pieces; + + // Find the source (HEK, CCMC, RHESSI, WSA) and label for this event_type + $source = null; + $label = null; + foreach (EventTypeCatalogue::MAP as $src => $types) { + if (array_key_exists($event_type, $types)) { + $source = $src; + $label = $types[$event_type]; + break; + } + } + + // Skip if event_type not found in map + if ($source === null || $label === null) { + continue; + } + + $frms = explode(";", $combined_frms); + + // If 'all' or empty frms, just use SOURCE>>LABEL + if (empty($combined_frms) || $combined_frms === 'all' || in_array('all', $frms)) { + $selections[] = $source . '>>' . $label; + } else { + // For each specific FRM, create SOURCE>>LABEL>>FRM + foreach ($frms as $frm) { + $frm = trim($frm); + if (!empty($frm)) { + $selections[] = $source . '>>' . $label . '>>' . $frm; + } + } + } + } + } + + return $selections; + } + + /** + * Convenience for the URL-params screenshot/movie endpoints: parse the + * ?events= string into selection paths and pair it with a per-source + * visibility map derived from the global ?eventLabels= flag. + * + * The legacy URL format has no per-source marker toggle, so markers are + * uniformly visible; label_visibility comes from $labels. + * + * @param string $events_state_string the ?events= value + * @param bool $labels the ?eventLabels= value + * @return array{0: string[], 1: array} + */ + public static function selectionsFromUrlParams(string $events_state_string, bool $labels): array + { + return [self::parse($events_state_string), self::visibilityFromLabels($labels)]; + } + + /** + * Build a per-source visibility map from the global eventLabels flag. + * Markers are always visible (the legacy URL API has no per-source marker + * toggle); label_visibility comes from $labels. One entry per known source. + * + * @return array + */ + public static function visibilityFromLabels(bool $labels): array + { + $visibility = []; + foreach (array_keys(EventTypeCatalogue::MAP) as $source) { + $visibility[$source] = [ + 'marker_visibility' => true, + 'label_visibility' => $labels, + ]; + } + + return $visibility; + } +} diff --git a/src/Event/Timeline/CoverageInterface.php b/src/Event/Timeline/CoverageInterface.php index be882cd87..fe93db526 100644 --- a/src/Event/Timeline/CoverageInterface.php +++ b/src/Event/Timeline/CoverageInterface.php @@ -12,7 +12,7 @@ interface CoverageInterface /** * @param EventsApiInterface $eventsApi * @param TimeRange $range Extended time range - * @param array $paths Selection paths from EventSelections + * @param array $paths Canonical SOURCE>>Label[>>FRM] selection paths * @param string $resolution Resolution string * @return array Series data for the timeline */ diff --git a/src/Event/Timeline/Timeline.php b/src/Event/Timeline/Timeline.php index aaf213392..a757885fe 100644 --- a/src/Event/Timeline/Timeline.php +++ b/src/Event/Timeline/Timeline.php @@ -4,7 +4,6 @@ use Helioviewer\Api\Event\Api\EventsApi; use Helioviewer\Api\Event\Api\EventsApiInterface; -use Helioviewer\Api\Event\EventSelections; /** * Orchestrator for event coverage timeline queries. @@ -14,19 +13,21 @@ * and returns JSON for the frontend timeline. * * Usage: - * $timeline = new Timeline($eventLayers, $start, $end, $current, $eventsApi); + * $timeline = new Timeline($paths, $start, $end, $current, $eventsApi); * echo $timeline->execute(); */ class Timeline { private TimeRange $range; private string $resolution; - private EventSelections $eventSelections; + /** @var string[] canonical SOURCE>>Label[>>FRM] selection paths */ + private array $paths; private EventsApiInterface $eventsApi; private CoverageInterface $strategy; /** - * @param string $eventLayers Legacy event string e.g. '[AR,all,1],[FL,NOAA_SWPC,1]' + * @param string[] $paths Canonical selection paths, e.g. + * ['HEK>>Active Region', 'WSA>>Magnetic Connectivity>>SO'] * @param mixed $startTimestamp Start time in milliseconds * @param mixed $endTimestamp End time in milliseconds * @param mixed $currentTimestamp Current observation time in milliseconds @@ -35,7 +36,7 @@ class Timeline * @throws \InvalidArgumentException If timestamps are invalid */ public function __construct( - string $eventLayers, + array $paths, $startTimestamp, $endTimestamp, $currentTimestamp, @@ -48,8 +49,8 @@ public function __construct( // Calculate resolution from the time range $this->resolution = Resolution::fromRange($this->range->range()); - // Parse legacy event string into API selection paths - $this->eventSelections = EventSelections::buildFromLegacyEventStrings($eventLayers); + // Canonical selection paths, as sent by the eventsDataCoverage POST body. + $this->paths = array_values($paths); // API client — use provided or create default $this->eventsApi = $eventsApi ?? new EventsApi(); @@ -67,12 +68,10 @@ public function __construct( */ public function execute(): string { - $paths = iterator_to_array($this->eventSelections); - $data = $this->strategy->execute( $this->eventsApi, $this->range, - $paths, + $this->paths, $this->resolution ); @@ -82,5 +81,6 @@ public function execute(): string // Getters for testing public function getResolution(): string { return $this->resolution; } public function getRange(): TimeRange { return $this->range; } - public function getEventSelections(): EventSelections { return $this->eventSelections; } + /** @return string[] */ + public function getPaths(): array { return $this->paths; } } diff --git a/src/Image/Composite/HelioviewerCompositeImage.php b/src/Image/Composite/HelioviewerCompositeImage.php index e0e80f3c0..7a39d6efe 100644 --- a/src/Image/Composite/HelioviewerCompositeImage.php +++ b/src/Image/Composite/HelioviewerCompositeImage.php @@ -61,6 +61,7 @@ class Image_Composite_HelioviewerCompositeImage { 'SR' => '9DA4FF', 'HY' => 'CA89FF', 'NR' => 'FFD391', + 'MC' => 'B0C4FF', ]; /** @@ -92,7 +93,6 @@ public static function resolveMarkerPath(string $baseDir, string $type): string protected $height; protected $interlace; protected $layers; - protected $eventsManager; protected $movieIcons; protected $scale; protected $scaleType; @@ -131,7 +131,7 @@ public static function resolveMarkerPath(string $baseDir, string $type): string * * @return void */ - public function __construct($layers, $eventsManager, $movieIcons, $celestialBodies, $scale, $scaleType, $scaleX, $scaleY, $obsDate, $roi, $options) { + public function __construct($layers, EventContext $eventContext, $movieIcons, $celestialBodies, $scale, $scaleType, $scaleX, $scaleY, $obsDate, $roi, $options) { set_time_limit(90); // Extend time limit to avoid timeouts @@ -152,7 +152,6 @@ public function __construct($layers, $eventsManager, $movieIcons, $celestialBodi 'grayscale' => false, 'eclipse' => false, 'moon' => false, - 'eventContext' => EventContext::empty(), ); $options = array_replace($defaults, $options); @@ -162,9 +161,8 @@ public function __construct($layers, $eventsManager, $movieIcons, $celestialBodi $this->imageScale = $roi->imageScale(); $this->db = $options['database'] ? $options['database'] : new Database_ImgIndex(); - $this->eventContext = $options['eventContext']; + $this->eventContext = $eventContext; $this->layers = $layers; - $this->eventsManager = $eventsManager; $this->movieIcons = $movieIcons; $this->scale = $scale; $this->scaleType = $scaleType; @@ -642,26 +640,13 @@ private function _addEventLayer($imagickImage) { if (empty($events_to_render)) return; // Draw event footprint polygons onto the composite image. - // Footprint is an array of {x, y} points in HPC arcseconds (already rotated by Events API). - // We convert each point from arcseconds to pixel coordinates relative to the ROI, - // then draw a semi-transparent yellow polygon matching the frontend SVG style. + // Footprint is a list of rings; each ring is a list of {x, y} points in HPC arcseconds + // (already rotated by Events API). We convert each point from arcseconds to pixel + // coordinates relative to the ROI, then draw one polygon per ring matching the + // frontend SVG style. foreach ($events_to_render as $event) { if (empty($event['footprint'])) continue; - // Convert HPC arcseconds to pixel coordinates: - // px_x = (hpc_x - roi_left) / imageScale - timeOffsetX - // px_y = (-hpc_y - roi_top) / imageScale - timeOffsetY (Y negated: HPC up → pixel down) - $polyArray = []; - foreach ($event['footprint'] as $point) { - $polyArray[] = [ - 'x' => (( $point['x'] - $this->roi->left()) / $this->roi->imageScale()) - $this->_timeOffsetX, - 'y' => ((-$point['y'] - $this->roi->top() ) / $this->roi->imageScale()) - $this->_timeOffsetY, - ]; - } - - // Need at least 3 points to form a polygon - if (count($polyArray) < 3) continue; - // Match frontend SVG spec: // - Fill: per-type color (fallback #d4d4d4) at 40% opacity (0x66) // - Stroke: black at ~53% opacity (0x88), 1.5px, round joins @@ -673,9 +658,28 @@ private function _addEventLayer($imagickImage) { $draw->setStrokeWidth(1.5); $draw->setStrokeAntialias(true); $draw->setFillColor('#' . $fillHex . '66'); - $draw->polygon($polyArray); - $imagickImage->drawImage($draw); + // Convert HPC arcseconds to pixel coordinates per ring: + // px_x = (hpc_x - roi_left) / imageScale - timeOffsetX + // px_y = (-hpc_y - roi_top) / imageScale - timeOffsetY (Y negated: HPC up → pixel down) + $anyRingDrawn = false; + foreach ($event['footprint'] as $ring) { + $polyArray = []; + foreach ($ring as $point) { + $polyArray[] = [ + 'x' => (( $point['x'] - $this->roi->left()) / $this->roi->imageScale()) - $this->_timeOffsetX, + 'y' => ((-$point['y'] - $this->roi->top() ) / $this->roi->imageScale()) - $this->_timeOffsetY, + ]; + } + // Need at least 3 points to form a polygon + if (count($polyArray) < 3) continue; + $draw->polygon($polyArray); + $anyRingDrawn = true; + } + + if ($anyRingDrawn) { + $imagickImage->drawImage($draw); + } $draw->destroy(); } diff --git a/src/Image/Composite/HelioviewerMovieFrame.php b/src/Image/Composite/HelioviewerMovieFrame.php index 3a680565e..510bc9f8d 100644 --- a/src/Image/Composite/HelioviewerMovieFrame.php +++ b/src/Image/Composite/HelioviewerMovieFrame.php @@ -18,9 +18,9 @@ class Image_Composite_HelioviewerMovieFrame extends Image_Composite_HelioviewerC /** * Helioviewer movie frame */ - public function __construct($filepath, $layers, $eventsManager, $movieIcons, $celestialBodies, $scale, $scaleType, $scaleX, $scaleY, $obsDate, $roi, $options) + public function __construct($filepath, $layers, $eventContext, $movieIcons, $celestialBodies, $scale, $scaleType, $scaleX, $scaleY, $obsDate, $roi, $options) { - parent::__construct($layers, $eventsManager, $movieIcons, $celestialBodies, $scale, $scaleType, $scaleX, $scaleY, $obsDate, $roi, $options); + parent::__construct($layers, $eventContext, $movieIcons, $celestialBodies, $scale, $scaleType, $scaleX, $scaleY, $obsDate, $roi, $options); $this->build($filepath); } diff --git a/src/Image/Composite/HelioviewerScreenshot.php b/src/Image/Composite/HelioviewerScreenshot.php index f26019c62..65fb88fb6 100644 --- a/src/Image/Composite/HelioviewerScreenshot.php +++ b/src/Image/Composite/HelioviewerScreenshot.php @@ -22,9 +22,9 @@ class Image_Composite_HelioviewerScreenshot extends Image_Composite_HelioviewerC /** * Creates a new screenshot */ - public function __construct($layers, $eventsManager, $movieIcons, $celestialBodies, $scale, $scaleType, $scaleX, $scaleY, $obsDate, $roi, $options) { + public function __construct($layers, $eventContext, $movieIcons, $celestialBodies, $scale, $scaleType, $scaleX, $scaleY, $obsDate, $roi, $options) { - parent::__construct($layers, $eventsManager, $movieIcons, $celestialBodies, $scale, $scaleType, $scaleX, $scaleY, $obsDate, $roi, $options); + parent::__construct($layers, $eventContext, $movieIcons, $celestialBodies, $scale, $scaleType, $scaleX, $scaleY, $obsDate, $roi, $options); if ( array_key_exists('action', $options) && $options['action'] == 'downloadScreenshot' ) { @@ -76,7 +76,7 @@ private function _getScreenshotId() $this->watermark, $this->layers->serialize(), $this->layers->getBitMask(), - $this->eventsManager->export(), + $this->eventContext->exportEventsStateBlob(), $this->movieIcons, $this->scale, $this->scaleType, diff --git a/src/Module/Movies.php b/src/Module/Movies.php index 29f5cfb43..4cb6c1a83 100644 --- a/src/Module/Movies.php +++ b/src/Module/Movies.php @@ -14,7 +14,7 @@ */ use Helioviewer\Api\Module\BaseModule; use Helioviewer\Api\Module\ModuleInterface; -use Helioviewer\Api\Event\EventsStateManager; +use Helioviewer\Api\Event\LegacyEventsStringParser; use Helioviewer\Api\Sentry\Sentry; class Module_Movies extends BaseModule implements ModuleInterface { @@ -112,7 +112,12 @@ public function postMovie() { throw new Exception('Invalid layer choices! You must specify 1-5 comma-separated layer names.', 22); } - $events_manager = EventsStateManager::buildFromEventsState($json_params['eventsState']); + // Client sends event_selections + event_visibility_selections directly; + // persist that shape verbatim into the movies row for later rehydration. + $events_state_blob = json_encode([ + 'event_selections' => $json_params['event_selections'] ?? [], + 'event_visibility_selections' => $json_params['event_visibility_selections'] ?? [], + ]); // TODO 2012/04/11 // Discard any layers which do not share an overlap with the roi to @@ -169,7 +174,7 @@ public function postMovie() { $options['watermark'], $json_params['layers'], $bitmask, - $events_manager->export(), + $events_state_blob, (isset($json_params['movieIcons']) ? $json_params['movieIcons'] : false), (isset($json_params['followViewport']) ? $json_params['followViewport'] : false), $options['scale'], @@ -302,11 +307,15 @@ public function queueMovie() { $event_labels = (bool)$this->_params['eventLabels']; } - // ATTENTION! These two fields eventsLabels and eventSourceString needs to be kept in DB schema - // We are keeping them to support old takeScreenshot , queueMovie requests - - // Events manager built from old logic - $events_manager = EventsStateManager::buildFromLegacyEventStrings($events_legacy_string, $event_labels); + // Parse the legacy ?events= bracket-string into the canonical shape and + // persist it verbatim, so the movie worker rehydrates it exactly like a + // JSON postMovie row. + [$selections, $visibilitySelections] = + LegacyEventsStringParser::selectionsFromUrlParams($events_legacy_string, $event_labels); + $events_state_blob = json_encode([ + 'event_selections' => $selections, + 'event_visibility_selections' => $visibilitySelections, + ]); // TODO 2012/04/11 // Discard any layers which do not share an overlap with the roi to @@ -363,7 +372,7 @@ public function queueMovie() { $options['watermark'], $this->_params['layers'], $bitmask, - $events_manager->export(), + $events_state_blob, (isset($this->_params['movieIcons']) ? $this->_params['movieIcons'] : false), (isset($this->_params['followViewport']) ? $this->_params['followViewport'] : false), $options['scale'], diff --git a/src/Module/WebClient.php b/src/Module/WebClient.php index 94ef3b2ef..7177d89dc 100644 --- a/src/Module/WebClient.php +++ b/src/Module/WebClient.php @@ -18,7 +18,7 @@ use Helioviewer\Api\Module\BaseModule; use Helioviewer\Api\Module\ModuleInterface; -use Helioviewer\Api\Event\EventsStateManager; +use Helioviewer\Api\Event\LegacyEventsStringParser; use Helioviewer\Api\Event\EventContext; use Helioviewer\Api\Event\Timeline\Timeline as EventTimeline; use Helioviewer\Api\Event\Api\EventsApiException; @@ -504,14 +504,12 @@ public function postScreenshot() } - $events_manager = EventsStateManager::buildFromEventsState($json_params['eventsState']); - $screenshotDate = $json_params['date']; $totalStart = microtime(true); $eventContext = EventContext::build( - timestamps: [$screenshotDate], - selections: $events_manager->getSelections(), - visibilitySelections: $events_manager->getVisibilitySelections(), + frameTimestamps: [$screenshotDate], + selections: $json_params['event_selections'] ?? [], + visibilitySelections: $json_params['event_visibility_selections'] ?? [], api: $this->eventsApi(), logLabel: "Screenshot:{$screenshotDate}", ); @@ -525,7 +523,8 @@ public function postScreenshot() Sentry::setContext('Screenshot Request Variables',[ 'layers' => $layers, - 'events_manager' => $events_manager, + 'event_selections' => $json_params['event_selections'] ?? [], + 'event_visibility_selections' => $json_params['event_visibility_selections'] ?? [], 'movieIcons' => $movieIcons, 'celestialBodies' => $celestialBodies, 'scale' => $scale, @@ -539,7 +538,7 @@ public function postScreenshot() // Create the screenshot $screenshot = new Image_Composite_HelioviewerScreenshot( $layers, - $events_manager, + $eventContext, $movieIcons, $celestialBodies, $scale, @@ -548,7 +547,7 @@ public function postScreenshot() $scaleY, $json_params['date'], $roi, - array_merge($json_params, ['eventContext' => $eventContext]) + $json_params ); // Display screenshot @@ -615,30 +614,34 @@ public function takeScreenshot() { ); } - // Event legacy string - $events_legacy_string = ""; - if ( array_key_exists('events', $this->_params) ) { - $events_legacy_string = $this->_params['events']; - } - - // Event legacy labels switch - $event_labels = false; - if ( array_key_exists('eventLabels', $this->_params) ) { - $event_labels = (bool)$this->_params['eventLabels']; + // eventLabels sets per-source label visibility (markers always on) and + // applies to whichever event param is used. Optional; defaults off. + $event_labels = array_key_exists('eventLabels', $this->_params) ? (bool)$this->_params['eventLabels'] : false; + $visibilitySelections = LegacyEventsStringParser::visibilityFromLabels($event_labels); + + // Selections. Precedence: event_selections (canonical) first, then the + // legacy ?events= bracket-string, then none. Both params are optional. + // The composite persists $selections + $visibilitySelections (via + // EventContext) as the new-shape blob -- so a URL-params screenshot row is + // indistinguishable from a JSON postScreenshot row. + if ( array_key_exists('event_selections', $this->_params) ) { + // Canonical: semicolon-separated "SOURCE>>Label[>>FRM]" paths, e.g. + // event_selections=HEK>>Active Region;WSA>>Magnetic Connectivity>>SO + $parts = array_map('trim', explode(';', $this->_params['event_selections'])); + $selections = array_values(array_filter($parts, fn($p) => $p !== '')); + } elseif ( array_key_exists('events', $this->_params) ) { + // Legacy bracket-string. + $selections = LegacyEventsStringParser::parse($this->_params['events']); + } else { + $selections = []; } - - // ATTENTION! These two fields eventsLabels and eventSourceString needs to be kept in DB schema - // We are keeping them to support old takeScreenshot , queueMovie requests - // Events manager built from old logic - $events_manager = EventsStateManager::buildFromLegacyEventStrings($events_legacy_string, $event_labels); - $screenshotDate = $this->_params['date']; $totalStart = microtime(true); $eventContext = EventContext::build( - timestamps: [$screenshotDate], - selections: $events_manager->getSelections(), - visibilitySelections: $events_manager->getVisibilitySelections(), + frameTimestamps: [$screenshotDate], + selections: $selections, + visibilitySelections: $visibilitySelections, api: $this->eventsApi(), logLabel: "Screenshot:{$screenshotDate}", ); @@ -653,7 +656,7 @@ public function takeScreenshot() { // Create the screenshot $screenshot = new Image_Composite_HelioviewerScreenshot( $layers, - $events_manager, + $eventContext, $movieIcons, $celestialBodies, $scale, @@ -662,7 +665,7 @@ public function takeScreenshot() { $scaleY, $this->_params['date'], $roi, - array_merge($this->_options, ['eventContext' => $eventContext]) + $this->_options ); // Display screenshot @@ -744,25 +747,18 @@ public function reTakeScreenshot($screenshotId) { 'layer names.', 22); } - // Event Layers - $events_state_from_metadata = json_decode($metaData['eventsState'], true); - $events_manager; - - // ATTENTION! These two fields eventsLabels and eventSourceString needs to be kept in DB schema - // We are keeping them to support old takeScreenshot , queueMovie requests - - if(!empty($events_state_from_metadata)) { - $events_manager = EventsStateManager::buildFromEventsState($events_state_from_metadata); - } else { - $events_manager = EventsStateManager::buildFromLegacyEventStrings($metaData['eventSourceString'], (bool)$metaData['eventsLabels']); - } + // Event Layers — the persisted blob is the canonical shape; every row + // is converted by the deploy-time migration scripts, so read it directly. + $events_state_from_metadata = json_decode($metaData['eventsState'], true) ?? []; + $selections = $events_state_from_metadata['event_selections'] ?? []; + $visibilitySelections = $events_state_from_metadata['event_visibility_selections'] ?? []; $screenshotDate = $metaData['observationDate']; $totalStart = microtime(true); $eventContext = EventContext::build( - timestamps: [$screenshotDate], - selections: $events_manager->getSelections(), - visibilitySelections: $events_manager->getVisibilitySelections(), + frameTimestamps: [$screenshotDate], + selections: $selections, + visibilitySelections: $visibilitySelections, api: $this->eventsApi(), logLabel: "Screenshot:{$screenshotDate}", ); @@ -781,7 +777,7 @@ public function reTakeScreenshot($screenshotId) { // Create the screenshot $screenshot = new Image_Composite_HelioviewerScreenshot( $layers, - $events_manager, + $eventContext, (bool)$metaData['movieIcons'], $celestialBodies, (bool)$metaData['scale'], @@ -790,7 +786,7 @@ public function reTakeScreenshot($screenshotId) { $metaData['scaleY'], $metaData['observationDate'], $roi, - array_merge($options, ['eventContext' => $eventContext]) + $options ); } @@ -1010,8 +1006,11 @@ public function getDataCoverage() { return $this->getDataCoverageForLayers(); } else if (!empty($this->_options['eventLayers'])) { try { + // Legacy callers still pass the bracket-string; parse it into + // canonical paths for the (now path-based) Timeline. + $paths = LegacyEventsStringParser::parse($this->_options['eventLayers']); $timeline = new EventTimeline( - $this->_options['eventLayers'], + $paths, $this->_options['startDate'] ?? null, $this->_options['endDate'] ?? null, $this->_options['currentDate'] ?? null, @@ -1030,6 +1029,43 @@ public function getDataCoverage() { } } + /** + * API Endpoint: eventsDataCoverage + * + * POST replacement for the eventLayers half of getDataCoverage. Takes + * canonical selection paths in the JSON body instead of legacy event-type + * pins in the query string. + * + * Query params: currentDate, startDate, endDate (ms epoch) + * Body: { "event_selections": ["SOURCE>>Label>>FRM", ...] } + * + * Response shape unchanged from getDataCoverage's eventLayers branch -- + * see docs for eventsDataCoverage. + */ + public function eventsDataCoverage() { + try { + $json_params = $this->_params['json'] ?? []; + $paths = $json_params['event_selections'] ?? []; + + $timeline = new EventTimeline( + $paths, + $this->_params['startDate'] ?? null, + $this->_params['endDate'] ?? null, + $this->_params['currentDate'] ?? null, + $this->eventsApi() + ); + $this->_printJSON($timeline->execute()); + } catch (InvalidArgumentException $e) { + return $this->_sendResponse(400, 'Invalid time parameters', $e->getMessage()); + } catch (Exception $e) { + // EventsApiException already captured to Sentry by EventsApi + if (!($e instanceof EventsApiException)) { + Sentry::capture($e); + } + return $this->_sendResponse(500, 'Internal server error', $e->getMessage()); + } + } + /** * Returns data coverage for IMAGE layers. * Queries the data_coverage_30_min table for image availability data. @@ -1380,9 +1416,6 @@ public function getEclipseImage() { // ATTENTION! These two fields eventsLabels and eventSourceString needs to be kept in DB schema // We are keeping them to support old takeScreenshot , queueMovie requests - // Create empty events object required for screenshots. - $events_manager = EventsStateManager::buildFromLegacyEventStrings('', false); - // Create empty celestial bodies list $celestialBodies = array( "labels" => "", "trajectories" => ""); @@ -1391,7 +1424,7 @@ public function getEclipseImage() { include_once HV_ROOT_DIR.'/../src/Image/Composite/HelioviewerScreenshot.php'; $screenshot = new Image_Composite_HelioviewerScreenshot( $layers, - $events_manager, + EventContext::empty(), false, $celestialBodies, false, @@ -1750,6 +1783,13 @@ public function getValidationRules(): array { 'legacy_event_string' => array('eventLayers') ); break; + case 'eventsDataCoverage': + $expected = array( + 'required' => array('startDate', 'endDate', 'currentDate', 'json'), + 'ints' => array('startDate', 'endDate', 'currentDate'), + 'schema' => array('json' => 'https://api.helioviewer.org/schema/events_data_coverage.schema.json'), + ); + break; case 'getDataCoverageTimeline': $expected = array( 'optional' => array('resolution', 'endDate'), @@ -1775,7 +1815,7 @@ public function getValidationRules(): array { 'required' => array('date', 'imageScale', 'layers'), 'optional' => array('display', 'watermark', 'x1', 'x2', 'y1', 'y2', 'x0', 'y0', 'width', 'height', - 'events', 'eventLabels', 'movieIcons', 'scale', + 'events', 'event_selections', 'eventLabels', 'movieIcons', 'scale', 'scaleType', 'scaleX', 'scaleY', 'callback', 'switchSources', 'celestialBodiesLabels', 'celestialBodiesTrajectories'), 'floats' => array('imageScale', 'x1', 'x2', 'y1', 'y2', @@ -1786,6 +1826,7 @@ public function getValidationRules(): array { 'scale', 'movieIcons', 'switchSources'), 'alphanum' => array('scaleType', 'callback', 'celestialBodiesLabels', 'celestialBodiesTrajectories'), 'legacy_event_string' => array('events'), + 'any' => array('event_selections'), 'choices' => array('scaleType' => ['earth', 'scalebar']), 'layer' => array('layers') ); diff --git a/src/Movie/HelioviewerMovie.php b/src/Movie/HelioviewerMovie.php index b8dd212bf..f7ab120b1 100644 --- a/src/Movie/HelioviewerMovie.php +++ b/src/Movie/HelioviewerMovie.php @@ -35,7 +35,6 @@ require_once HV_ROOT_DIR . '/../src/Helper/RegionOfInterest.php'; require_once HV_ROOT_DIR . '/../src/Helper/Serialize.php'; -use Helioviewer\Api\Event\EventsStateManager; use Helioviewer\Api\Event\EventContext; use Helioviewer\Api\Event\Api\EventsApi; use Helioviewer\Api\Sentry\Sentry; @@ -87,7 +86,9 @@ class Movie_HelioviewerMovie { private $_db; private $_layers; - private $_eventsManager; + private $_selections = []; + private $_visibilitySelections = []; + private $_eventsStateBlob = []; private $_roi; private $_timestamps = array(); private $_frames = array(); @@ -169,14 +170,15 @@ public function __construct($publicId, $format='mp4') { // ATTENTION! These two fields eventsLabels and eventSourceString needs to be kept in DB schema // We are keeping them to support old takeScreenshot , queueMovie requests - // Events Manager - $events_state_from_info = json_decode($info['eventsState'], true); - - if(!empty($events_state_from_info)) { - $this->_eventsManager = EventsStateManager::buildFromEventsState($events_state_from_info); - } else { - $this->_eventsManager = EventsStateManager::buildFromLegacyEventStrings($info['eventSourceString'], (bool)$info['eventsLabels']); - } + // The persisted eventsState blob is the canonical shape: + // { event_selections: [...], event_visibility_selections: {...} } + // Every pre-existing row is converted to this shape by the deploy-time + // migration scripts, so the worker reads it directly with no + // legacy-shape branch. + $events_state_from_info = json_decode($info['eventsState'], true) ?? []; + $this->_eventsStateBlob = $events_state_from_info; + $this->_selections = $events_state_from_info['event_selections'] ?? []; + $this->_visibilitySelections = $events_state_from_info['event_visibility_selections'] ?? []; // Regon of interest $this->_roi = Helper_RegionOfInterest::parsePolygonString($info['roi'], $info['imageScale']); @@ -337,7 +339,7 @@ public function getCompletedMovieInformation($verbose=false) { 'duration' => $this->_getDuration(), 'imageScale' => $this->imageScale, 'layers' => $this->_layers->serialize(), - 'events' => $this->_eventsManager->getState(), + 'events' => $this->_eventsStateBlob, 'x1' => $this->_roi->left(), 'y1' => $this->_roi->top(), 'x2' => $this->_roi->right(), @@ -541,9 +543,9 @@ private function _buildMovieFrames($watermark) { $contextStart = microtime(true); $eventContext = EventContext::build( - timestamps: $timestamps, - selections: $this->_eventsManager->getSelections(), - visibilitySelections: $this->_eventsManager->getVisibilitySelections(), + frameTimestamps: $timestamps, + selections: $this->_selections, + visibilitySelections: $this->_visibilitySelections, api: new EventsApi(), chunkSize: $chunkSize, logLabel: "Movie:{$movieId}", @@ -558,8 +560,6 @@ private function _buildMovieFrames($watermark) { $contextMs )); - $options['eventContext'] = $eventContext; - // Index of preview frame $previewIndex = floor($this->numFrames/2); @@ -579,7 +579,7 @@ private function _buildMovieFrames($watermark) { try { $frameStart = microtime(true); $screenshot = new Image_Composite_HelioviewerMovieFrame( - $filepath, $this->_layers, $this->_eventsManager, + $filepath, $this->_layers, $eventContext, $this->movieIcons, $this->celestialBodies, $this->scale, $this->scaleType, $this->scaleX, $this->scaleY, $time, $this->_roi, $options); diff --git a/tests/unit_tests/events/EventContextTest.php b/tests/unit_tests/events/EventContextTest.php index 0974d28f5..25dfd5b01 100644 --- a/tests/unit_tests/events/EventContextTest.php +++ b/tests/unit_tests/events/EventContextTest.php @@ -82,12 +82,12 @@ public function testHappyPathShiftsFootprintByRotationDelta(): void 'path' => 'HEK>>Active Region>>SPoCA', 'hv_hpc_x' => 100.0, 'hv_hpc_y' => 200.0, - 'footprint' => [['x' => 110.0, 'y' => 210.0]], + 'footprint' => [[['x' => 110.0, 'y' => 210.0]]], ], ], 'timestamps' => [ $ts => [ - $eventId => ['hv_hpc_x' => 120.0, 'hv_hpc_y' => 230.0], + $eventId => ['dx' => 20.0, 'dy' => 30.0], ], ], ]); @@ -96,9 +96,12 @@ public function testHappyPathShiftsFootprintByRotationDelta(): void $events = $context->getEventsForDate($ts); $this->assertCount(1, $events); - // dx = 120 - 100 = 20, dy = 230 - 200 = 30. Footprint point (110, 210) -> (130, 240). - $this->assertSame(130.0, $events[0]['footprint'][0]['x']); - $this->assertSame(240.0, $events[0]['footprint'][0]['y']); + // Upstream sends dx=20, dy=30 directly. + // Footprint point (110, 210) + (dx, dy) -> (130, 240). + // Marker: canonical (100, 200) + (dx, dy) -> (120, 230). + // Footprint is a list of rings; single-ring, single-point fixture -> [0][0]. + $this->assertSame(130.0, $events[0]['footprint'][0][0]['x']); + $this->assertSame(240.0, $events[0]['footprint'][0][0]['y']); $this->assertSame(120.0, $events[0]['hv_hpc_x']); $this->assertSame(230.0, $events[0]['hv_hpc_y']); $this->assertTrue($context->hasEvents()); @@ -121,7 +124,7 @@ public function testHiddenLabelIsEncodedAsEmptyString(): void ], 'timestamps' => [ $ts => [ - $eventId => ['hv_hpc_x' => 0.0, 'hv_hpc_y' => 0.0], + $eventId => ['dx' => 0.0, 'dy' => 0.0], ], ], ]); @@ -153,7 +156,7 @@ public function testVisibleLabelDefaultsToTrueWhenSourceMissingFromVisibilityMap ], ], 'timestamps' => [ - $ts => [$eventId => ['hv_hpc_x' => 0.0, 'hv_hpc_y' => 0.0]], + $ts => [$eventId => ['dx' => 0.0, 'dy' => 0.0]], ], ]); @@ -174,8 +177,7 @@ public function testGetEventsForDateOnUnknownDateLogsToSentryWhenContextNonEmpty ->method('setContext') ->with('EventContext', $this->callback(function ($params) { return array_key_exists('requested_date', $params) - && array_key_exists('available_dates', $params) - && array_key_exists('events_by_date', $params); + && array_key_exists('available_dates', $params); })); $this->mockSentry->expects($this->once())->method('message'); @@ -206,7 +208,7 @@ public function testHasEventsReturnsTrueWhenAtLeastOneDateHasEvents(): void ], ], 'timestamps' => [ - $ts1 => [$eventId => ['hv_hpc_x' => 0.0, 'hv_hpc_y' => 0.0]], + $ts1 => [$eventId => ['dx' => 0.0, 'dy' => 0.0]], $ts2 => [], ], ]); diff --git a/tests/unit_tests/events/EventTreeTest.php b/tests/unit_tests/events/EventTreeTest.php index 0887879fa..c191e2933 100644 --- a/tests/unit_tests/events/EventTreeTest.php +++ b/tests/unit_tests/events/EventTreeTest.php @@ -93,7 +93,7 @@ public function testItCreatesDynamicBucketAndReportsUnknownPath(): void $this->sentry->expects($this->once()) ->method('message') ->with($this->equalTo( - 'simpletree: encountered paths not in EventSelections::$event_types_map' + 'simpletree: encountered paths not in EventTypeCatalogue::MAP' )); $event = ['path' => 'HEK>>NewConcept>>SomeFRM', 'id' => 'x']; diff --git a/tests/unit_tests/events/EventSelectionsTest.php b/tests/unit_tests/events/LegacyEventsStringParserTest.php similarity index 58% rename from tests/unit_tests/events/EventSelectionsTest.php rename to tests/unit_tests/events/LegacyEventsStringParserTest.php index 2d59e28d8..1a6b7def6 100644 --- a/tests/unit_tests/events/EventSelectionsTest.php +++ b/tests/unit_tests/events/LegacyEventsStringParserTest.php @@ -1,13 +1,19 @@ */ use PHPUnit\Framework\TestCase; -use Helioviewer\Api\Event\EventSelections; +use Helioviewer\Api\Event\LegacyEventsStringParser; -final class EventSelectionsTest extends TestCase +final class LegacyEventsStringParserTest extends TestCase { public static function legacyStringProvider(): array { @@ -32,6 +38,10 @@ public static function legacyStringProvider(): array '[F2,all,1]', ['RHESSI>>Solar Flares'], ], + 'wsa_source' => [ + '[MC,SO,1]', + ['WSA>>Magnetic Connectivity>>SO'], + ], 'multiple_groups' => [ '[AR,all,1],[FL,all,1]', ['HEK>>Active Region', 'HEK>>Flare'], @@ -86,31 +96,29 @@ public static function legacyStringProvider(): array /** * @dataProvider legacyStringProvider */ - public function testItShouldBuildCorrectSelectionsFromLegacyString(string $input, array $expected): void + public function testItParsesLegacyStringsToPaths(string $input, array $expected): void { - $selections = EventSelections::buildFromLegacyEventStrings($input); - $this->assertEquals($expected, iterator_to_array($selections)); + $this->assertSame($expected, LegacyEventsStringParser::parse($input)); } - public function testItShouldBeCountableIterableAndArrayAccessible(): void + public function testSelectionsFromUrlParamsPairsPathsWithVisibility(): void { - $selections = EventSelections::buildFromLegacyEventStrings('[AR,all,1],[FL,all,1]'); + [$selections, $visibility] = LegacyEventsStringParser::selectionsFromUrlParams('[AR,all,1],[MC,SO,1]', true); - // Countable - $this->assertCount(2, $selections); + $this->assertSame(['HEK>>Active Region', 'WSA>>Magnetic Connectivity>>SO'], $selections); - // Iterable - $paths = []; - foreach ($selections as $path) { - $paths[] = $path; + // One entry per known source; markers always visible, labels from the flag. + $this->assertEqualsCanonicalizing(['HEK', 'CCMC', 'RHESSI', 'WSA'], array_keys($visibility)); + foreach ($visibility as $flags) { + $this->assertSame(['marker_visibility' => true, 'label_visibility' => true], $flags); } - $this->assertEquals(['HEK>>Active Region', 'HEK>>Flare'], $paths); + } + + public function testSelectionsFromUrlParamsPropagatesLabelsFlagFalse(): void + { + [, $visibility] = LegacyEventsStringParser::selectionsFromUrlParams('[AR,all,1]', false); - // ArrayAccess - $this->assertEquals('HEK>>Active Region', $selections[0]); - $this->assertEquals('HEK>>Flare', $selections[1]); - $this->assertTrue(isset($selections[0])); - $this->assertFalse(isset($selections[99])); - $this->assertNull($selections[99]); + $this->assertFalse($visibility['HEK']['label_visibility']); + $this->assertTrue($visibility['HEK']['marker_visibility']); } } diff --git a/tests/unit_tests/events/api/EventsApiTest.php b/tests/unit_tests/events/api/EventsApiTest.php index edb031427..884edd17b 100644 --- a/tests/unit_tests/events/api/EventsApiTest.php +++ b/tests/unit_tests/events/api/EventsApiTest.php @@ -32,42 +32,4 @@ public function testConstructorSetsDefaultSentryContext(): void new EventsApi($this->mockClient, $this->mockSentry); } - - public static function filterSourcesProvider(): array - { - return [ - 'all_valid' => [ - ['HEK', 'CCMC', 'RHESSI'], - ['HEK', 'CCMC', 'RHESSI'], - ], - 'mixed_valid_and_invalid' => [ - ['HEK', 'FOO', 'BAR'], - ['HEK'], - ], - 'tree_prefixed_rejected' => [ - ['tree_HEK', 'tree_CCMC'], - [], - ], - 'empty_input' => [ - [], - [], - ], - 'all_invalid' => [ - ['FOO', 'BAR', 'BAZ'], - [], - ], - 'single_valid' => [ - ['CCMC'], - ['CCMC'], - ], - ]; - } - - /** - * @dataProvider filterSourcesProvider - */ - public function testItShouldFilterSources(array $input, array $expected): void - { - $this->assertEquals($expected, EventsApi::filterSources($input)); - } } diff --git a/tests/unit_tests/events/api/GetEventsBatchTest.php b/tests/unit_tests/events/api/GetEventsBatchTest.php deleted file mode 100644 index a871248ae..000000000 --- a/tests/unit_tests/events/api/GetEventsBatchTest.php +++ /dev/null @@ -1,161 +0,0 @@ - - */ - -use PHPUnit\Framework\TestCase; -use GuzzleHttp\ClientInterface; -use GuzzleHttp\Psr7\Response; -use Helioviewer\Api\Event\Api\EventsApi; -use Helioviewer\Api\Event\Api\EventsApiException; -use Helioviewer\Api\Event\Api\LegacyEventsInterface; -use Helioviewer\Api\Sentry\ClientInterface as SentryClientInterface; - -final class GetEventsBatchTest extends TestCase -{ - private $mockClient; - private $mockSentry; - private $mockLegacyEvents; - private $eventsApi; - - protected function setUp(): void - { - $this->mockClient = $this->createMock(ClientInterface::class); - $this->mockSentry = $this->createMock(SentryClientInterface::class); - $this->mockLegacyEvents = $this->createMock(LegacyEventsInterface::class); - $this->eventsApi = new EventsApi($this->mockClient, $this->mockSentry, $this->mockLegacyEvents); - } - - public function testItShouldReturnEmptyForEmptyTimestamps(): void - { - $this->mockClient->expects($this->never())->method('request'); - $this->mockLegacyEvents->expects($this->never())->method('convertAll'); - - $result = $this->eventsApi->getEventsBatch([], ['HEK']); - $this->assertEquals([], $result); - } - - public function testItShouldThrowForInvalidSources(): void - { - $this->mockClient->expects($this->never())->method('request'); - - $this->expectException(EventsApiException::class); - $this->expectExceptionMessage('No valid sources given'); - - $this->eventsApi->getEventsBatch(['2024-01-15 12:00:00'], ['FOO', 'BAR']); - } - - public function testItShouldCallCorrectUrlWithJoinedSourcesAndTimestamps(): void - { - $batchResponse = ['event_types' => [], 'events' => [], 'observations' => []]; - - $this->mockClient->expects($this->once()) - ->method('request') - ->with('POST', '/helioviewer/events/HEK::CCMC/observations', $this->callback(function ($options) { - return $options['json']['timestamps'] === ['2024-01-15 12:00:00', '2024-01-15 12:01:00']; - })) - ->willReturn(new Response(200, [], json_encode($batchResponse))); - - $this->mockLegacyEvents->method('convertAll')->willReturn([]); - - $this->eventsApi->getEventsBatch( - ['2024-01-15 12:00:00', '2024-01-15 12:01:00'], - ['HEK', 'CCMC'] - ); - } - - public function testItShouldPaginateTimestampsAt150(): void - { - $timestamps = []; - for ($i = 0; $i < 200; $i++) { - $timestamps[] = "2024-01-15 " . sprintf('%02d:%02d:00', intdiv($i, 60), $i % 60); - } - - $batchResponse = ['event_types' => [], 'events' => [], 'observations' => []]; - - $this->mockClient->expects($this->exactly(2)) - ->method('request') - ->withConsecutive( - ['POST', '/helioviewer/events/HEK/observations', $this->callback(function ($options) { - return count($options['json']['timestamps']) === 150; - })], - ['POST', '/helioviewer/events/HEK/observations', $this->callback(function ($options) { - return count($options['json']['timestamps']) === 50; - })] - ) - ->willReturn(new Response(200, [], json_encode($batchResponse))); - - $this->mockLegacyEvents->method('convertAll')->willReturn([]); - - $this->eventsApi->getEventsBatch($timestamps, ['HEK'], 150); - } - - public function testItShouldThrowAndCaptureSentryOnHttpError(): void - { - $this->mockClient->method('request') - ->willThrowException(new \RuntimeException('connection refused')); - - $this->mockSentry->expects($this->atLeastOnce()) - ->method('setContext') - ->with('EventsApi', $this->callback(function ($params) { - return array_key_exists('error', $params) || array_key_exists('endpoint', $params) || array_key_exists('api_url', $params); - })); - - $this->mockSentry->expects($this->once()) - ->method('capture') - ->with($this->isInstanceOf(EventsApiException::class)); - - $this->expectException(EventsApiException::class); - $this->expectExceptionMessage('Failed to fetch batch events: connection refused'); - - $this->eventsApi->getEventsBatch(['2024-01-15 12:00:00'], ['HEK']); - } - - public function testItShouldMergeObservationsAcrossChunksAndPassToConverter(): void - { - $timestamps = []; - for ($i = 0; $i < 160; $i++) { - $timestamps[] = "2024-01-15 " . sprintf('%02d:%02d:00', intdiv($i, 60), $i % 60); - } - - $chunk1Response = [ - 'event_types' => [['pin' => 'AR', 'name' => 'Active Region', 'groups' => []]], - 'events' => ['evt1' => ['label' => 'AR 1']], - 'observations' => [ - '2024-01-15 00:00:00' => ['evt1' => ['hv_hpc_x' => 1.0, 'hv_hpc_y' => 2.0]], - '2024-01-15 00:01:00' => ['evt1' => ['hv_hpc_x' => 1.1, 'hv_hpc_y' => 2.1]], - ] - ]; - - $chunk2Response = [ - 'event_types' => [['pin' => 'AR', 'name' => 'Active Region', 'groups' => []]], - 'events' => ['evt1' => ['label' => 'AR 1']], - 'observations' => [ - '2024-01-15 02:30:00' => ['evt1' => ['hv_hpc_x' => 3.0, 'hv_hpc_y' => 4.0]], - ] - ]; - - $this->mockClient->expects($this->exactly(2)) - ->method('request') - ->willReturnOnConsecutiveCalls( - new Response(200, [], json_encode($chunk1Response)), - new Response(200, [], json_encode($chunk2Response)) - ); - - // Verify convertAll receives merged observations from both chunks - $this->mockLegacyEvents->expects($this->once()) - ->method('convertAll') - ->with($this->callback(function ($merged) { - $obs = $merged['observations']; - return count($obs) === 3 - && isset($obs['2024-01-15 00:00:00']) - && isset($obs['2024-01-15 00:01:00']) - && isset($obs['2024-01-15 02:30:00']) - && $obs['2024-01-15 02:30:00']['evt1']['hv_hpc_x'] == 3.0; - })) - ->willReturn([]); - - $this->eventsApi->getEventsBatch($timestamps, ['HEK'], 150); - } -} diff --git a/tests/unit_tests/events/api/GetEventsForFramesWithSelectionsTest.php b/tests/unit_tests/events/api/GetEventsForFramesWithSelectionsTest.php index 64d3a9622..5bd2c48a2 100644 --- a/tests/unit_tests/events/api/GetEventsForFramesWithSelectionsTest.php +++ b/tests/unit_tests/events/api/GetEventsForFramesWithSelectionsTest.php @@ -9,22 +9,19 @@ use GuzzleHttp\Psr7\Response; use Helioviewer\Api\Event\Api\EventsApi; use Helioviewer\Api\Event\Api\EventsApiException; -use Helioviewer\Api\Event\Api\LegacyEventsInterface; use Helioviewer\Api\Sentry\ClientInterface as SentryClientInterface; final class GetEventsForFramesWithSelectionsTest extends TestCase { private $mockClient; private $mockSentry; - private $mockLegacyEvents; private $eventsApi; protected function setUp(): void { $this->mockClient = $this->createMock(ClientInterface::class); $this->mockSentry = $this->createMock(SentryClientInterface::class); - $this->mockLegacyEvents = $this->createMock(LegacyEventsInterface::class); - $this->eventsApi = new EventsApi($this->mockClient, $this->mockSentry, $this->mockLegacyEvents); + $this->eventsApi = new EventsApi($this->mockClient, $this->mockSentry); } public function testItShouldThrowForEmptySelections(): void @@ -78,10 +75,10 @@ public function testItShouldFallBackToConfiguredChunkSizeWhenCallerPassesLessTha $this->mockClient->expects($this->exactly(2)) ->method('request') ->withConsecutive( - ['POST', '/helioviewer/events/frames_with_selections', $this->callback(function ($options) use ($fallbackChunk) { + ['POST', '/helioviewer/events/frames_with_selections?withDelta', $this->callback(function ($options) use ($fallbackChunk) { return count($options['json']['timestamps']) === $fallbackChunk; })], - ['POST', '/helioviewer/events/frames_with_selections', $this->callback(function ($options) use ($tail) { + ['POST', '/helioviewer/events/frames_with_selections?withDelta', $this->callback(function ($options) use ($tail) { return count($options['json']['timestamps']) === $tail; })] ) @@ -103,10 +100,10 @@ public function testItShouldCapChunkSizeAtUpstreamLimit(): void $this->mockClient->expects($this->exactly(2)) ->method('request') ->withConsecutive( - ['POST', '/helioviewer/events/frames_with_selections', $this->callback(function ($options) { + ['POST', '/helioviewer/events/frames_with_selections?withDelta', $this->callback(function ($options) { return count($options['json']['timestamps']) === 150; })], - ['POST', '/helioviewer/events/frames_with_selections', $this->callback(function ($options) { + ['POST', '/helioviewer/events/frames_with_selections?withDelta', $this->callback(function ($options) { return count($options['json']['timestamps']) === 50; })] ) @@ -129,15 +126,15 @@ public function testItShouldPaginateTimestampsAtTheGivenChunkSize(): void $this->mockClient->expects($this->exactly(3)) ->method('request') ->withConsecutive( - ['POST', '/helioviewer/events/frames_with_selections', $this->callback(function ($options) { + ['POST', '/helioviewer/events/frames_with_selections?withDelta', $this->callback(function ($options) { return count($options['json']['timestamps']) === 3 && $options['json']['selections'] === ['HEK>>Flare', 'CCMC>>DONKI>>CME']; })], - ['POST', '/helioviewer/events/frames_with_selections', $this->callback(function ($options) { + ['POST', '/helioviewer/events/frames_with_selections?withDelta', $this->callback(function ($options) { return count($options['json']['timestamps']) === 3 && $options['json']['selections'] === ['HEK>>Flare', 'CCMC>>DONKI>>CME']; })], - ['POST', '/helioviewer/events/frames_with_selections', $this->callback(function ($options) { + ['POST', '/helioviewer/events/frames_with_selections?withDelta', $this->callback(function ($options) { return count($options['json']['timestamps']) === 1 && $options['json']['selections'] === ['HEK>>Flare', 'CCMC>>DONKI>>CME']; })] diff --git a/tests/unit_tests/events/api/LegacyEventsTest.php b/tests/unit_tests/events/api/LegacyEventsTest.php deleted file mode 100644 index 38843136f..000000000 --- a/tests/unit_tests/events/api/LegacyEventsTest.php +++ /dev/null @@ -1,268 +0,0 @@ - - */ - -use PHPUnit\Framework\TestCase; -use Helioviewer\Api\Event\Api\LegacyEvents; - -final class LegacyEventsTest extends TestCase -{ - private LegacyEvents $converter; - - protected function setUp(): void - { - $this->converter = new LegacyEvents(); - } - - public static function convertProvider(): array - { - return [ - 'single_event_single_group' => [ - // eventTypes - [ - ['pin' => 'AR', 'name' => 'Active Region', 'groups' => [ - ['name' => 'SPoCA', 'event_ids' => ['evt1']] - ]] - ], - // events - [ - 'evt1' => ['label' => 'AR 12345', 'type' => 'AR', 'hv_hpc_x' => 100.0, 'hv_hpc_y' => 200.0] - ], - // observations - [ - 'evt1' => ['hv_hpc_x' => 105.0, 'hv_hpc_y' => 210.0] - ], - // expected categories count - 1, - // expected first category pin - 'AR', - // expected first event hv_hpc_x - 105.0, - ], - 'multiple_groups' => [ - [ - ['pin' => 'AR', 'name' => 'Active Region', 'groups' => [ - ['name' => 'SPoCA', 'event_ids' => ['evt1']], - ['name' => 'SHARP', 'event_ids' => ['evt2']], - ]] - ], - [ - 'evt1' => ['label' => 'AR 1', 'type' => 'AR', 'hv_hpc_x' => 100.0, 'hv_hpc_y' => 200.0], - 'evt2' => ['label' => 'AR 2', 'type' => 'AR', 'hv_hpc_x' => 300.0, 'hv_hpc_y' => 400.0], - ], - [ - 'evt1' => ['hv_hpc_x' => 101.0, 'hv_hpc_y' => 201.0], - 'evt2' => ['hv_hpc_x' => 301.0, 'hv_hpc_y' => 401.0], - ], - 1, - 'AR', - 101.0, - ], - 'multiple_categories' => [ - [ - ['pin' => 'AR', 'name' => 'Active Region', 'groups' => [ - ['name' => 'SPoCA', 'event_ids' => ['evt1']] - ]], - ['pin' => 'FL', 'name' => 'Flare', 'groups' => [ - ['name' => 'SWPC', 'event_ids' => ['evt2']] - ]], - ], - [ - 'evt1' => ['label' => 'AR 1', 'type' => 'AR', 'hv_hpc_x' => 100.0, 'hv_hpc_y' => 200.0], - 'evt2' => ['label' => 'FL 1', 'type' => 'FL', 'hv_hpc_x' => 500.0, 'hv_hpc_y' => 600.0], - ], - [ - 'evt1' => ['hv_hpc_x' => 101.0, 'hv_hpc_y' => 201.0], - 'evt2' => ['hv_hpc_x' => 501.0, 'hv_hpc_y' => 601.0], - ], - 2, - 'AR', - 101.0, - ], - 'empty_event_types' => [ - [], - [], - [], - 0, - null, - null, - ], - 'empty_observations' => [ - [ - ['pin' => 'AR', 'name' => 'Active Region', 'groups' => [ - ['name' => 'SPoCA', 'event_ids' => ['evt1']] - ]] - ], - [ - 'evt1' => ['label' => 'AR 1', 'type' => 'AR', 'hv_hpc_x' => 100.0, 'hv_hpc_y' => 200.0], - ], - [], - 0, - null, - null, - ], - ]; - } - - /** - * @dataProvider convertProvider - */ - public function testItShouldConvertToLegacyFormat( - array $eventTypes, - array $events, - array $obs, - int $expectedCategoryCount, - ?string $expectedFirstPin, - ?float $expectedFirstHpcX - ): void { - $result = $this->converter->convert($eventTypes, $events, $obs); - - $this->assertCount($expectedCategoryCount, $result); - - if ($expectedFirstPin !== null) { - $this->assertEquals($expectedFirstPin, $result[0]['pin']); - } - - if ($expectedFirstHpcX !== null) { - $event = $result[0]['groups'][0]['data'][0]; - $this->assertEquals($expectedFirstHpcX, $event['hv_hpc_x']); - $this->assertEquals($expectedFirstHpcX, $event['hv_hpc_x_final']); - } - } - - public function testItShouldMergeRotatedCoords(): void - { - $result = $this->converter->convert( - [['pin' => 'AR', 'name' => 'Active Region', 'groups' => [ - ['name' => 'SPoCA', 'event_ids' => ['evt1']] - ]]], - ['evt1' => ['label' => 'AR 1', 'type' => 'AR', 'hv_hpc_x' => 100.0, 'hv_hpc_y' => 200.0]], - ['evt1' => ['hv_hpc_x' => 105.0, 'hv_hpc_y' => 210.0]] - ); - - $event = $result[0]['groups'][0]['data'][0]; - $this->assertEquals(105.0, $event['hv_hpc_x']); - $this->assertEquals(210.0, $event['hv_hpc_y']); - $this->assertEquals(105.0, $event['hv_hpc_x_final']); - $this->assertEquals(210.0, $event['hv_hpc_y_final']); - } - - public function testItShouldSkipInactiveEvents(): void - { - $result = $this->converter->convert( - [['pin' => 'AR', 'name' => 'Active Region', 'groups' => [ - ['name' => 'SPoCA', 'event_ids' => ['evt1', 'evt2']] - ]]], - [ - 'evt1' => ['label' => 'AR 1', 'type' => 'AR', 'hv_hpc_x' => 100.0, 'hv_hpc_y' => 200.0], - 'evt2' => ['label' => 'AR 2', 'type' => 'AR', 'hv_hpc_x' => 300.0, 'hv_hpc_y' => 400.0], - ], - // only evt1 active - ['evt1' => ['hv_hpc_x' => 101.0, 'hv_hpc_y' => 201.0]] - ); - - $data = $result[0]['groups'][0]['data']; - $this->assertCount(1, $data); - $this->assertEquals('AR 1', $data[0]['label']); - } - - public function testItShouldShiftFootprintByRotationDelta(): void - { - $result = $this->converter->convert( - [['pin' => 'AR', 'name' => 'Active Region', 'groups' => [ - ['name' => 'SPoCA', 'event_ids' => ['evt1']] - ]]], - ['evt1' => [ - 'label' => 'AR 1', 'type' => 'AR', - 'hv_hpc_x' => 100.0, 'hv_hpc_y' => 200.0, - 'footprint' => [ - ['x' => 98.0, 'y' => 198.0], - ['x' => 102.0, 'y' => 202.0], - ] - ]], - ['evt1' => ['hv_hpc_x' => 105.0, 'hv_hpc_y' => 210.0]] - ); - - $footprint = $result[0]['groups'][0]['data'][0]['footprint']; - // dx = 105 - 100 = 5, dy = 210 - 200 = 10 - $this->assertEquals(103.0, $footprint[0]['x']); - $this->assertEquals(208.0, $footprint[0]['y']); - $this->assertEquals(107.0, $footprint[1]['x']); - $this->assertEquals(212.0, $footprint[1]['y']); - } - - public function testItShouldExcludeEmptyGroups(): void - { - $result = $this->converter->convert( - [['pin' => 'AR', 'name' => 'Active Region', 'groups' => [ - ['name' => 'SPoCA', 'event_ids' => ['evt1']], - ['name' => 'SHARP', 'event_ids' => ['evt2']], - ]]], - [ - 'evt1' => ['label' => 'AR 1', 'type' => 'AR', 'hv_hpc_x' => 100.0, 'hv_hpc_y' => 200.0], - 'evt2' => ['label' => 'AR 2', 'type' => 'AR', 'hv_hpc_x' => 300.0, 'hv_hpc_y' => 400.0], - ], - // only evt1 active, evt2 not → SHARP group should be excluded - ['evt1' => ['hv_hpc_x' => 101.0, 'hv_hpc_y' => 201.0]] - ); - - $this->assertCount(1, $result[0]['groups']); - $this->assertEquals('SPoCA', $result[0]['groups'][0]['name']); - } - - public function testItShouldExcludeEmptyCategories(): void - { - $result = $this->converter->convert( - [ - ['pin' => 'AR', 'name' => 'Active Region', 'groups' => [ - ['name' => 'SPoCA', 'event_ids' => ['evt1']] - ]], - ['pin' => 'FL', 'name' => 'Flare', 'groups' => [ - ['name' => 'SWPC', 'event_ids' => ['evt2']] - ]], - ], - [ - 'evt1' => ['label' => 'AR 1', 'type' => 'AR', 'hv_hpc_x' => 100.0, 'hv_hpc_y' => 200.0], - 'evt2' => ['label' => 'FL 1', 'type' => 'FL', 'hv_hpc_x' => 500.0, 'hv_hpc_y' => 600.0], - ], - // only evt1 active → FL category excluded - ['evt1' => ['hv_hpc_x' => 101.0, 'hv_hpc_y' => 201.0]] - ); - - $this->assertCount(1, $result); - $this->assertEquals('AR', $result[0]['pin']); - } - - public function testItShouldConvertAllTimestamps(): void - { - $batchResponse = [ - 'event_types' => [ - ['pin' => 'AR', 'name' => 'Active Region', 'groups' => [ - ['name' => 'SPoCA', 'event_ids' => ['evt1']] - ]] - ], - 'events' => [ - 'evt1' => ['label' => 'AR 1', 'type' => 'AR', 'hv_hpc_x' => 100.0, 'hv_hpc_y' => 200.0], - ], - 'observations' => [ - '2024-01-15 12:00:00' => ['evt1' => ['hv_hpc_x' => 101.0, 'hv_hpc_y' => 201.0]], - '2024-01-15 12:01:00' => ['evt1' => ['hv_hpc_x' => 102.0, 'hv_hpc_y' => 202.0]], - '2024-01-15 12:02:00' => ['evt1' => ['hv_hpc_x' => 103.0, 'hv_hpc_y' => 203.0]], - ] - ]; - - $result = $this->converter->convertAll($batchResponse); - - $this->assertCount(3, $result); - $this->assertArrayHasKey('2024-01-15 12:00:00', $result); - $this->assertArrayHasKey('2024-01-15 12:01:00', $result); - $this->assertArrayHasKey('2024-01-15 12:02:00', $result); - - // Each timestamp has its own rotated coords - $this->assertEquals(101.0, $result['2024-01-15 12:00:00'][0]['groups'][0]['data'][0]['hv_hpc_x']); - $this->assertEquals(102.0, $result['2024-01-15 12:01:00'][0]['groups'][0]['data'][0]['hv_hpc_x']); - $this->assertEquals(103.0, $result['2024-01-15 12:02:00'][0]['groups'][0]['data'][0]['hv_hpc_x']); - } -} diff --git a/tests/unit_tests/events/timeline/TimelineTest.php b/tests/unit_tests/events/timeline/TimelineTest.php index 0d323d273..efdac833b 100644 --- a/tests/unit_tests/events/timeline/TimelineTest.php +++ b/tests/unit_tests/events/timeline/TimelineTest.php @@ -34,7 +34,7 @@ public function testItShouldPassCorrectParamsToStrategy(): void && $range->extendedStart() === -1000 && $range->extendedEnd() === 5000; }), - // [AR,all,1],[C3,all,1] → paths + // canonical paths, passed straight through $this->equalTo(['HEK>>Active Region', 'CCMC>>DONKI']), // Range 2000ms → minute resolution $this->equalTo('m') @@ -42,7 +42,7 @@ public function testItShouldPassCorrectParamsToStrategy(): void ->willReturn([]); $timeline = new Timeline( - '[AR,all,1],[C3,all,1]', 1000, 3000, 2000, + ['HEK>>Active Region', 'CCMC>>DONKI'], 1000, 3000, 2000, $this->mockEventsApi, $this->mockStrategy ); @@ -60,7 +60,7 @@ public function testItShouldReturnJsonEncodedStrategyOutput(): void $this->mockStrategy->method('execute')->willReturn($strategyOutput); $timeline = new Timeline( - '[AR,all,1]', 1000, 2000, 1500, + ['HEK>>Active Region'], 1000, 2000, 1500, $this->mockEventsApi, $this->mockStrategy ); diff --git a/tests/unit_tests/module/test_data/invalid.json b/tests/unit_tests/module/test_data/invalid.json index ab5cb1676..a561a2ebb 100644 --- a/tests/unit_tests/module/test_data/invalid.json +++ b/tests/unit_tests/module/test_data/invalid.json @@ -1,111 +1,104 @@ { - "date": 1712557812000, - "centerX": -172.3873528481749, - "centerY": "-216.25766746329495", - "imageScale": 0.60511022, - "eventLayers": { - "tree_HEK": { - "id": "HEK", - "layers": [], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": false - }, - "tree_CCMC": { - "id": "CCMC", - "layers": [], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": true - }, - "tree_RHESSI": { - "id": "RHESSI", - "layers": [], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": true - } - }, - "imageLayers": [ - { - "end": "2024-04-08 06:30:13", - "start": "2024-04-08 06:19:24", - "opacity": 35, - "visible": true, - "diffTime": 1, - "nickname": "IRIS SJI 2796", - "sourceId": 89, - "uiLabels": [ - { - "name": "IRIS", - "label": "Observatory" + "date": 1712557812000, + "centerX": -172.3873528481749, + "centerY": "-216.25766746329495", + "imageScale": 0.60511022, + "event_selections": [], + "event_visibility_selections": { + "HEK": { + "marker_visibility": true, + "label_visibility": true }, - { - "name": "SJI", - "label": "Instrument" + "CCMC": { + "marker_visibility": true, + "label_visibility": true }, - { - "name": "2796", - "label": "Measurement" + "RHESSI": { + "marker_visibility": true, + "label_visibility": true + }, + "WSA": { + "marker_visibility": true, + "label_visibility": true } - ], - "diffCount": 60, - "Instrument": "SJI", - "difference": 0, - "Measurement": "2796", - "Observatory": "IRIS", - "baseDiffTime": "2024/06/12 08:32:57", - "layeringOrder": 1 }, - { - "end": "2024-06-11 06:38:14", - "start": "2012-07-05 00:09:05", - "opacity": 100, - "visible": "1", - "diffTime": 1, - "nickname": "AIA 1600", - "sourceId": 15, - "uiLabels": [ - { - "name": "SDO", - "label": "Observatory" - }, + "imageLayers": [ { - "name": "AIA", - "label": "Instrument" + "end": "2024-04-08 06:30:13", + "start": "2024-04-08 06:19:24", + "opacity": 35, + "visible": true, + "diffTime": 1, + "nickname": "IRIS SJI 2796", + "sourceId": 89, + "uiLabels": [ + { + "name": "IRIS", + "label": "Observatory" + }, + { + "name": "SJI", + "label": "Instrument" + }, + { + "name": "2796", + "label": "Measurement" + } + ], + "diffCount": 60, + "Instrument": "SJI", + "difference": 0, + "Measurement": "2796", + "Observatory": "IRIS", + "baseDiffTime": "2024/06/12 08:32:57", + "layeringOrder": 1 }, { - "name": "1600", - "label": "Measurement" + "end": "2024-06-11 06:38:14", + "start": "2012-07-05 00:09:05", + "opacity": 100, + "visible": "1", + "diffTime": 1, + "nickname": "AIA 1600", + "sourceId": 15, + "uiLabels": [ + { + "name": "SDO", + "label": "Observatory" + }, + { + "name": "AIA", + "label": "Instrument" + }, + { + "name": "1600", + "label": "Measurement" + } + ], + "diffCount": 60, + "Instrument": "AIA", + "difference": 0, + "Measurement": "1600", + "Observatory": "SDO", + "baseDiffTime": "2024/04/08 05:30:13", + "layeringOrder": 1 } - ], - "diffCount": 60, - "Instrument": "AIA", - "difference": 0, - "Measurement": "1600", - "Observatory": "SDO", - "baseDiffTime": "2024/04/08 05:30:13", - "layeringOrder": 1 - } - ], - "celestialBodies": { - "soho": [ - "soho-mercury-tree-label", - "soho-venus-tree-label", - "soho-mars-tree-label", - "soho-jupiter-tree-label", - "soho-saturn-tree-label", - "soho-uranus-tree-label", - "soho-neptune-tree-label" - ], - "stereo_a": [ - "stereo_a-mercury-tree-label" ], - "stereo_b": [ - "stereo_b-mercury-tree-label" - ] - } + "celestialBodies": { + "soho": [ + "soho-mercury-tree-label", + "soho-venus-tree-label", + "soho-mars-tree-label", + "soho-jupiter-tree-label", + "soho-saturn-tree-label", + "soho-uranus-tree-label", + "soho-neptune-tree-label" + ], + "stereo_a": [ + "stereo_a-mercury-tree-label" + ], + "stereo_b": [ + "stereo_b-mercury-tree-label" + ] + } } diff --git a/tests/unit_tests/module/test_data/valid.json b/tests/unit_tests/module/test_data/valid.json index 90e3a3500..78af2879b 100644 --- a/tests/unit_tests/module/test_data/valid.json +++ b/tests/unit_tests/module/test_data/valid.json @@ -1,111 +1,104 @@ { - "date": 1712557812000, - "centerX": -172.3873528481749, - "centerY": -216.25766746329495, - "imageScale": 0.60511022, - "eventLayers": { - "tree_HEK": { - "id": "HEK", - "layers": [], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": false - }, - "tree_CCMC": { - "id": "CCMC", - "layers": [], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": true - }, - "tree_RHESSI": { - "id": "RHESSI", - "layers": [], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": true - } - }, - "imageLayers": [ - { - "end": "2024-04-08 06:30:13", - "start": "2024-04-08 06:19:24", - "opacity": 35, - "visible": true, - "diffTime": 1, - "nickname": "IRIS SJI 2796", - "sourceId": 89, - "uiLabels": [ - { - "name": "IRIS", - "label": "Observatory" + "date": 1712557812000, + "centerX": -172.3873528481749, + "centerY": -216.25766746329495, + "imageScale": 0.60511022, + "event_selections": [], + "event_visibility_selections": { + "HEK": { + "marker_visibility": true, + "label_visibility": true }, - { - "name": "SJI", - "label": "Instrument" + "CCMC": { + "marker_visibility": true, + "label_visibility": true }, - { - "name": "2796", - "label": "Measurement" + "RHESSI": { + "marker_visibility": true, + "label_visibility": true + }, + "WSA": { + "marker_visibility": true, + "label_visibility": true } - ], - "diffCount": 60, - "Instrument": "SJI", - "difference": 0, - "Measurement": "2796", - "Observatory": "IRIS", - "baseDiffTime": "2024-06-12T08:32:57.000Z", - "layeringOrder": 1 }, - { - "end": "2024-06-11 06:38:14", - "start": "2012-07-05 00:09:05", - "opacity": 100, - "visible": "1", - "diffTime": 1, - "nickname": "AIA 1600", - "sourceId": 15, - "uiLabels": [ - { - "name": "SDO", - "label": "Observatory" - }, + "imageLayers": [ { - "name": "AIA", - "label": "Instrument" + "end": "2024-04-08 06:30:13", + "start": "2024-04-08 06:19:24", + "opacity": 35, + "visible": true, + "diffTime": 1, + "nickname": "IRIS SJI 2796", + "sourceId": 89, + "uiLabels": [ + { + "name": "IRIS", + "label": "Observatory" + }, + { + "name": "SJI", + "label": "Instrument" + }, + { + "name": "2796", + "label": "Measurement" + } + ], + "diffCount": 60, + "Instrument": "SJI", + "difference": 0, + "Measurement": "2796", + "Observatory": "IRIS", + "baseDiffTime": "2024-06-12T08:32:57.000Z", + "layeringOrder": 1 }, { - "name": "1600", - "label": "Measurement" + "end": "2024-06-11 06:38:14", + "start": "2012-07-05 00:09:05", + "opacity": 100, + "visible": "1", + "diffTime": 1, + "nickname": "AIA 1600", + "sourceId": 15, + "uiLabels": [ + { + "name": "SDO", + "label": "Observatory" + }, + { + "name": "AIA", + "label": "Instrument" + }, + { + "name": "1600", + "label": "Measurement" + } + ], + "diffCount": 60, + "Instrument": "AIA", + "difference": 0, + "Measurement": "1600", + "Observatory": "SDO", + "baseDiffTime": "2024-04-08T05:30:13.000Z", + "layeringOrder": 1 } - ], - "diffCount": 60, - "Instrument": "AIA", - "difference": 0, - "Measurement": "1600", - "Observatory": "SDO", - "baseDiffTime": "2024-04-08T05:30:13.000Z", - "layeringOrder": 1 - } - ], - "celestialBodies": { - "soho": [ - "soho-mercury-tree-label", - "soho-venus-tree-label", - "soho-mars-tree-label", - "soho-jupiter-tree-label", - "soho-saturn-tree-label", - "soho-uranus-tree-label", - "soho-neptune-tree-label" - ], - "stereo_a": [ - "stereo_a-mercury-tree-label" ], - "stereo_b": [ - "stereo_b-mercury-tree-label" - ] - } + "celestialBodies": { + "soho": [ + "soho-mercury-tree-label", + "soho-venus-tree-label", + "soho-mars-tree-label", + "soho-jupiter-tree-label", + "soho-saturn-tree-label", + "soho-uranus-tree-label", + "soho-neptune-tree-label" + ], + "stereo_a": [ + "stereo_a-mercury-tree-label" + ], + "stereo_b": [ + "stereo_b-mercury-tree-label" + ] + } } diff --git a/tests/unit_tests/validation/test_data/client_state/valid/custom_event_layer_key.json b/tests/unit_tests/validation/test_data/client_state/valid/custom_event_layer_key.json index 3dd6b0cd5..fa2728bb1 100644 --- a/tests/unit_tests/validation/test_data/client_state/valid/custom_event_layer_key.json +++ b/tests/unit_tests/validation/test_data/client_state/valid/custom_event_layer_key.json @@ -1,103 +1,108 @@ { - "date": 1712557812000, - "centerX": -172.3873528481749, - "centerY": -216.25766746329495, - "imageScale": 0.60511022, - "eventLayers": { - "allowed": { - "labels_visible": true, - "layers": [{ - "event_type": "AR", - "frms": ["some_frm"], - "event_instances": ["AR--something--ok"] - }] - }, - "tree_HEK": { - "labels_visible": true, - "layers": [{ - "event_type": "AR", - "frms": ["some_frm"], - "event_instances": ["AR--something--ok"] - }] - } - }, - "imageLayers": [ - { - "end": "2024-04-08 06:30:13", - "start": "2024-04-08 06:19:24", - "opacity": 35, - "visible": true, - "diffTime": 1, - "nickname": "IRIS SJI 2796", - "sourceId": 89, - "uiLabels": [ - { - "name": "IRIS", - "label": "Observatory" + "date": 1712557812000, + "centerX": -172.3873528481749, + "centerY": -216.25766746329495, + "imageScale": 0.60511022, + "event_selections": [ + "HEK>>Active Region>>some_frm", + "HEK>>Active Region>>some frm", + "HEK>>Active Region>>something" + ], + "event_visibility_selections": { + "HEK": { + "marker_visibility": true, + "label_visibility": true }, - { - "name": "SJI", - "label": "Instrument" + "CCMC": { + "marker_visibility": true, + "label_visibility": true }, - { - "name": "2796", - "label": "Measurement" + "RHESSI": { + "marker_visibility": true, + "label_visibility": true + }, + "WSA": { + "marker_visibility": true, + "label_visibility": true } - ], - "diffCount": 60, - "Instrument": "SJI", - "difference": 0, - "Measurement": "2796", - "Observatory": "IRIS", - "baseDiffTime": "2024-06-12T08:32:57.000Z", - "layeringOrder": 1 }, - { - "end": "2024-06-11 06:38:14", - "start": "2012-07-05 00:09:05", - "opacity": 100, - "visible": "1", - "diffTime": 1, - "nickname": "AIA 1600", - "sourceId": 15, - "uiLabels": [ - { - "name": "SDO", - "label": "Observatory" - }, + "imageLayers": [ { - "name": "AIA", - "label": "Instrument" + "end": "2024-04-08 06:30:13", + "start": "2024-04-08 06:19:24", + "opacity": 35, + "visible": true, + "diffTime": 1, + "nickname": "IRIS SJI 2796", + "sourceId": 89, + "uiLabels": [ + { + "name": "IRIS", + "label": "Observatory" + }, + { + "name": "SJI", + "label": "Instrument" + }, + { + "name": "2796", + "label": "Measurement" + } + ], + "diffCount": 60, + "Instrument": "SJI", + "difference": 0, + "Measurement": "2796", + "Observatory": "IRIS", + "baseDiffTime": "2024-06-12T08:32:57.000Z", + "layeringOrder": 1 }, { - "name": "1600", - "label": "Measurement" + "end": "2024-06-11 06:38:14", + "start": "2012-07-05 00:09:05", + "opacity": 100, + "visible": "1", + "diffTime": 1, + "nickname": "AIA 1600", + "sourceId": 15, + "uiLabels": [ + { + "name": "SDO", + "label": "Observatory" + }, + { + "name": "AIA", + "label": "Instrument" + }, + { + "name": "1600", + "label": "Measurement" + } + ], + "diffCount": 60, + "Instrument": "AIA", + "difference": 0, + "Measurement": "1600", + "Observatory": "SDO", + "baseDiffTime": "2024-04-08T05:30:13.000Z", + "layeringOrder": 1 } - ], - "diffCount": 60, - "Instrument": "AIA", - "difference": 0, - "Measurement": "1600", - "Observatory": "SDO", - "baseDiffTime": "2024-04-08T05:30:13.000Z", - "layeringOrder": 1 - } - ], - "celestialBodies": { - "soho": [ - "soho-mercury-tree-label", - "soho-venus-tree-label", - "soho-mars-tree-label", - "soho-jupiter-tree-label", - "soho-saturn-tree-label", - "soho-uranus-tree-label", - "soho-neptune-tree-label" - ], - "stereo_a": [ - "stereo_a-mercury-tree-label" ], - "stereo_b": [ - "stereo_b-mercury-tree-label" - ] - } + "celestialBodies": { + "soho": [ + "soho-mercury-tree-label", + "soho-venus-tree-label", + "soho-mars-tree-label", + "soho-jupiter-tree-label", + "soho-saturn-tree-label", + "soho-uranus-tree-label", + "soho-neptune-tree-label" + ], + "stereo_a": [ + "stereo_a-mercury-tree-label" + ], + "stereo_b": [ + "stereo_b-mercury-tree-label" + ] + } } diff --git a/tests/unit_tests/validation/test_data/client_state/valid/minimal_event_group.json b/tests/unit_tests/validation/test_data/client_state/valid/minimal_event_group.json index 02a2f72ad..85a66b8a7 100644 --- a/tests/unit_tests/validation/test_data/client_state/valid/minimal_event_group.json +++ b/tests/unit_tests/validation/test_data/client_state/valid/minimal_event_group.json @@ -1,95 +1,108 @@ { - "date": 1712557812000, - "centerX": -172.3873528481749, - "centerY": -216.25766746329495, - "imageScale": 0.60511022, - "eventLayers": { - "tree_HEK": { - "labels_visible": true, - "layers": [{ - "event_type": "AR", - "frms": ["some_frm"], - "event_instances": ["AR--frm--encoded"] - }] - } - }, - "imageLayers": [ - { - "end": "2024-04-08 06:30:13", - "start": "2024-04-08 06:19:24", - "opacity": 35, - "visible": true, - "diffTime": 1, - "nickname": "IRIS SJI 2796", - "sourceId": 89, - "uiLabels": [ - { - "name": "IRIS", - "label": "Observatory" + "date": 1712557812000, + "centerX": -172.3873528481749, + "centerY": -216.25766746329495, + "imageScale": 0.60511022, + "event_selections": [ + "HEK>>Active Region>>some_frm", + "HEK>>Active Region>>some frm", + "HEK>>Active Region>>frm" + ], + "event_visibility_selections": { + "HEK": { + "marker_visibility": true, + "label_visibility": true }, - { - "name": "SJI", - "label": "Instrument" + "CCMC": { + "marker_visibility": true, + "label_visibility": true }, - { - "name": "2796", - "label": "Measurement" + "RHESSI": { + "marker_visibility": true, + "label_visibility": true + }, + "WSA": { + "marker_visibility": true, + "label_visibility": true } - ], - "diffCount": 60, - "Instrument": "SJI", - "difference": 0, - "Measurement": "2796", - "Observatory": "IRIS", - "baseDiffTime": "2024-06-12T08:32:57.000Z", - "layeringOrder": 1 }, - { - "end": "2024-06-11 06:38:14", - "start": "2012-07-05 00:09:05", - "opacity": 100, - "visible": "1", - "diffTime": 1, - "nickname": "AIA 1600", - "sourceId": 15, - "uiLabels": [ + "imageLayers": [ { - "name": "SDO", - "label": "Observatory" + "end": "2024-04-08 06:30:13", + "start": "2024-04-08 06:19:24", + "opacity": 35, + "visible": true, + "diffTime": 1, + "nickname": "IRIS SJI 2796", + "sourceId": 89, + "uiLabels": [ + { + "name": "IRIS", + "label": "Observatory" + }, + { + "name": "SJI", + "label": "Instrument" + }, + { + "name": "2796", + "label": "Measurement" + } + ], + "diffCount": 60, + "Instrument": "SJI", + "difference": 0, + "Measurement": "2796", + "Observatory": "IRIS", + "baseDiffTime": "2024-06-12T08:32:57.000Z", + "layeringOrder": 1 }, { - "name": "AIA", - "label": "Instrument" - }, - { - "name": "1600", - "label": "Measurement" + "end": "2024-06-11 06:38:14", + "start": "2012-07-05 00:09:05", + "opacity": 100, + "visible": "1", + "diffTime": 1, + "nickname": "AIA 1600", + "sourceId": 15, + "uiLabels": [ + { + "name": "SDO", + "label": "Observatory" + }, + { + "name": "AIA", + "label": "Instrument" + }, + { + "name": "1600", + "label": "Measurement" + } + ], + "diffCount": 60, + "Instrument": "AIA", + "difference": 0, + "Measurement": "1600", + "Observatory": "SDO", + "baseDiffTime": "2024-04-08T05:30:13.000Z", + "layeringOrder": 1 } - ], - "diffCount": 60, - "Instrument": "AIA", - "difference": 0, - "Measurement": "1600", - "Observatory": "SDO", - "baseDiffTime": "2024-04-08T05:30:13.000Z", - "layeringOrder": 1 - } - ], - "celestialBodies": { - "soho": [ - "soho-mercury-tree-label", - "soho-venus-tree-label", - "soho-mars-tree-label", - "soho-jupiter-tree-label", - "soho-saturn-tree-label", - "soho-uranus-tree-label", - "soho-neptune-tree-label" ], - "stereo_a": [ - "stereo_a-mercury-tree-label" - ], - "stereo_b": [ - "stereo_b-mercury-tree-label" - ] - } + "celestialBodies": { + "soho": [ + "soho-mercury-tree-label", + "soho-venus-tree-label", + "soho-mars-tree-label", + "soho-jupiter-tree-label", + "soho-saturn-tree-label", + "soho-uranus-tree-label", + "soho-neptune-tree-label" + ], + "stereo_a": [ + "stereo_a-mercury-tree-label" + ], + "stereo_b": [ + "stereo_b-mercury-tree-label" + ] + } } diff --git a/tests/unit_tests/validation/test_data/client_state/valid/valid_1.json b/tests/unit_tests/validation/test_data/client_state/valid/valid_1.json index 90e3a3500..78af2879b 100644 --- a/tests/unit_tests/validation/test_data/client_state/valid/valid_1.json +++ b/tests/unit_tests/validation/test_data/client_state/valid/valid_1.json @@ -1,111 +1,104 @@ { - "date": 1712557812000, - "centerX": -172.3873528481749, - "centerY": -216.25766746329495, - "imageScale": 0.60511022, - "eventLayers": { - "tree_HEK": { - "id": "HEK", - "layers": [], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": false - }, - "tree_CCMC": { - "id": "CCMC", - "layers": [], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": true - }, - "tree_RHESSI": { - "id": "RHESSI", - "layers": [], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": true - } - }, - "imageLayers": [ - { - "end": "2024-04-08 06:30:13", - "start": "2024-04-08 06:19:24", - "opacity": 35, - "visible": true, - "diffTime": 1, - "nickname": "IRIS SJI 2796", - "sourceId": 89, - "uiLabels": [ - { - "name": "IRIS", - "label": "Observatory" + "date": 1712557812000, + "centerX": -172.3873528481749, + "centerY": -216.25766746329495, + "imageScale": 0.60511022, + "event_selections": [], + "event_visibility_selections": { + "HEK": { + "marker_visibility": true, + "label_visibility": true }, - { - "name": "SJI", - "label": "Instrument" + "CCMC": { + "marker_visibility": true, + "label_visibility": true }, - { - "name": "2796", - "label": "Measurement" + "RHESSI": { + "marker_visibility": true, + "label_visibility": true + }, + "WSA": { + "marker_visibility": true, + "label_visibility": true } - ], - "diffCount": 60, - "Instrument": "SJI", - "difference": 0, - "Measurement": "2796", - "Observatory": "IRIS", - "baseDiffTime": "2024-06-12T08:32:57.000Z", - "layeringOrder": 1 }, - { - "end": "2024-06-11 06:38:14", - "start": "2012-07-05 00:09:05", - "opacity": 100, - "visible": "1", - "diffTime": 1, - "nickname": "AIA 1600", - "sourceId": 15, - "uiLabels": [ - { - "name": "SDO", - "label": "Observatory" - }, + "imageLayers": [ { - "name": "AIA", - "label": "Instrument" + "end": "2024-04-08 06:30:13", + "start": "2024-04-08 06:19:24", + "opacity": 35, + "visible": true, + "diffTime": 1, + "nickname": "IRIS SJI 2796", + "sourceId": 89, + "uiLabels": [ + { + "name": "IRIS", + "label": "Observatory" + }, + { + "name": "SJI", + "label": "Instrument" + }, + { + "name": "2796", + "label": "Measurement" + } + ], + "diffCount": 60, + "Instrument": "SJI", + "difference": 0, + "Measurement": "2796", + "Observatory": "IRIS", + "baseDiffTime": "2024-06-12T08:32:57.000Z", + "layeringOrder": 1 }, { - "name": "1600", - "label": "Measurement" + "end": "2024-06-11 06:38:14", + "start": "2012-07-05 00:09:05", + "opacity": 100, + "visible": "1", + "diffTime": 1, + "nickname": "AIA 1600", + "sourceId": 15, + "uiLabels": [ + { + "name": "SDO", + "label": "Observatory" + }, + { + "name": "AIA", + "label": "Instrument" + }, + { + "name": "1600", + "label": "Measurement" + } + ], + "diffCount": 60, + "Instrument": "AIA", + "difference": 0, + "Measurement": "1600", + "Observatory": "SDO", + "baseDiffTime": "2024-04-08T05:30:13.000Z", + "layeringOrder": 1 } - ], - "diffCount": 60, - "Instrument": "AIA", - "difference": 0, - "Measurement": "1600", - "Observatory": "SDO", - "baseDiffTime": "2024-04-08T05:30:13.000Z", - "layeringOrder": 1 - } - ], - "celestialBodies": { - "soho": [ - "soho-mercury-tree-label", - "soho-venus-tree-label", - "soho-mars-tree-label", - "soho-jupiter-tree-label", - "soho-saturn-tree-label", - "soho-uranus-tree-label", - "soho-neptune-tree-label" - ], - "stereo_a": [ - "stereo_a-mercury-tree-label" ], - "stereo_b": [ - "stereo_b-mercury-tree-label" - ] - } + "celestialBodies": { + "soho": [ + "soho-mercury-tree-label", + "soho-venus-tree-label", + "soho-mars-tree-label", + "soho-jupiter-tree-label", + "soho-saturn-tree-label", + "soho-uranus-tree-label", + "soho-neptune-tree-label" + ], + "stereo_a": [ + "stereo_a-mercury-tree-label" + ], + "stereo_b": [ + "stereo_b-mercury-tree-label" + ] + } } diff --git a/tests/unit_tests/validation/test_data/client_state/valid/valid_10.json b/tests/unit_tests/validation/test_data/client_state/valid/valid_10.json index 2698e01a1..021e1fa28 100644 --- a/tests/unit_tests/validation/test_data/client_state/valid/valid_10.json +++ b/tests/unit_tests/validation/test_data/client_state/valid/valid_10.json @@ -1,120 +1,81 @@ { - "date": 1715731311000, - "centerX": -3018.5704096094664, - "centerY": -410.28075595668, - "imageScale": 38.72705408, - "eventLayers": { - "tree_HEK": { - "id": "HEK", - "layers": [ - { - "frms": [ - "NOAA_SWPC_Observer" - ], - "open": 1, - "event_type": "AR", - "event_instances": [] + "date": 1715731311000, + "centerX": -3018.5704096094664, + "centerY": -410.28075595668, + "imageScale": 38.72705408, + "event_selections": [ + "CCMC>>DONKI>>CME", + "RHESSI>>Solar Flares" + ], + "event_visibility_selections": { + "HEK": { + "marker_visibility": false, + "label_visibility": false }, - { - "frms": [ - "EGSO_SFC" - ], - "open": 1, - "event_type": "SS", - "event_instances": [] - } - ], - "visible": true, - "labels_visible": false, - "markers_visible": false, - "layer_available_visible": false - }, - "tree_CCMC": { - "id": "CCMC", - "layers": [ - { - "frms": [ - "CME" - ], - "open": 1, - "event_type": "C3", - "event_instances": [] - } - ], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": false - }, - "tree_RHESSI": { - "id": "RHESSI", - "layers": [ - { - "frms": [ - "all" - ], - "open": 1, - "event_type": "F2", - "event_instances": [] - } - ], - "visible": true, - "labels_visible": false, - "markers_visible": true, - "layer_available_visible": true - } - }, - "imageLayers": [ - { - "opacity": 100, - "visible": true, - "diffTime": 1, - "uiLabels": [ - { - "name": "SDO", - "label": "Observatory" + "CCMC": { + "marker_visibility": true, + "label_visibility": true }, - { - "name": "AIA", - "label": "Instrument" + "RHESSI": { + "marker_visibility": true, + "label_visibility": false }, + "WSA": { + "marker_visibility": true, + "label_visibility": true + } + }, + "imageLayers": [ { - "name": "1600", - "label": "Measurement" + "opacity": 100, + "visible": true, + "diffTime": 1, + "uiLabels": [ + { + "name": "SDO", + "label": "Observatory" + }, + { + "name": "AIA", + "label": "Instrument" + }, + { + "name": "1600", + "label": "Measurement" + } + ], + "diffCount": 60, + "Instrument": "AIA", + "difference": 0, + "Measurement": "1600", + "Observatory": "SDO", + "baseDiffTime": "2024-06-17T10:49:02.000Z" } - ], - "diffCount": 60, - "Instrument": "AIA", - "difference": 0, - "Measurement": "1600", - "Observatory": "SDO", - "baseDiffTime": "2024-06-17T10:49:02.000Z" - } - ], - "celestialBodies": { - "soho": [ - "soho-mercury-tree-label", - "soho-mars-tree-label", - "soho-jupiter-tree-label", - "soho-uranus-tree-label" ], - "stereo_a": [ - "stereo_a-mercury-tree-label", - "stereo_a-venus-tree-label", - "stereo_a-earth-tree-label", - "stereo_a-mars-tree-label", - "stereo_a-jupiter-tree-label", - "stereo_a-saturn-tree-label", - "stereo_a-uranus-tree-label", - "stereo_a-neptune-tree-label", - "stereo_a-psp-tree-branch" - ], - "stereo_b": [ - "stereo_b-mercury-tree-label", - "stereo_b-earth-tree-label", - "stereo_b-mars-tree-label", - "stereo_b-jupiter-tree-label", - "stereo_b-saturn-tree-label" - ] - } + "celestialBodies": { + "soho": [ + "soho-mercury-tree-label", + "soho-mars-tree-label", + "soho-jupiter-tree-label", + "soho-uranus-tree-label" + ], + "stereo_a": [ + "stereo_a-mercury-tree-label", + "stereo_a-venus-tree-label", + "stereo_a-earth-tree-label", + "stereo_a-mars-tree-label", + "stereo_a-jupiter-tree-label", + "stereo_a-saturn-tree-label", + "stereo_a-uranus-tree-label", + "stereo_a-neptune-tree-label", + "stereo_a-psp-tree-branch" + ], + "stereo_b": [ + "stereo_b-mercury-tree-label", + "stereo_b-earth-tree-label", + "stereo_b-mars-tree-label", + "stereo_b-jupiter-tree-label", + "stereo_b-saturn-tree-label" + ] + } } diff --git a/tests/unit_tests/validation/test_data/client_state/valid/valid_11.json b/tests/unit_tests/validation/test_data/client_state/valid/valid_11.json index 8c8142c2f..021e1fa28 100644 --- a/tests/unit_tests/validation/test_data/client_state/valid/valid_11.json +++ b/tests/unit_tests/validation/test_data/client_state/valid/valid_11.json @@ -1,130 +1,81 @@ { - "date": 1715731311000, - "centerX": -3018.5704096094664, - "centerY": -410.28075595668, - "imageScale": 38.72705408, - "eventLayers": { - "tree_HEK": { - "id": "HEK", - "layers": [ - { - "frms": [], - "open": 1, - "event_type": "AR", - "event_instances": [ - "AR--NOAA_SWPC_Observer--aXZvOi8vaGVsaW8taW5mb3JtYXRpY3Mub3JnL0FSX05PQUFTV1BDT2JzZXJ2ZXJfMjAyNDA1MTVfMDI0ODIxX05PQUExMzY3MV8yMDI0MDUxNQ__", - "AR--NOAA_SWPC_Observer--aXZvOi8vaGVsaW8taW5mb3JtYXRpY3Mub3JnL0FSX05PQUFTV1BDT2JzZXJ2ZXJfMjAyNDA1MTVfMDI0ODIzX05PQUExMzY3Ml8yMDI0MDUxNQ__", - "AR--NOAA_SWPC_Observer--aXZvOi8vaGVsaW8taW5mb3JtYXRpY3Mub3JnL0FSX05PQUFTV1BDT2JzZXJ2ZXJfMjAyNDA1MTVfMDI0ODE5X05PQUExMzY3MF8yMDI0MDUxNQ__", - "AR--NOAA_SWPC_Observer--aXZvOi8vaGVsaW8taW5mb3JtYXRpY3Mub3JnL0FSX05PQUFTV1BDT2JzZXJ2ZXJfMjAyNDA1MTVfMDI0ODQwX05PQUExMzY4MF8yMDI0MDUxNQ__", - "AR--NOAA_SWPC_Observer--aXZvOi8vaGVsaW8taW5mb3JtYXRpY3Mub3JnL0FSX05PQUFTV1BDT2JzZXJ2ZXJfMjAyNDA1MTVfMDI0ODQzX05PQUExMzY4Ml8yMDI0MDUxNQ__", - "AR--NOAA_SWPC_Observer--aXZvOi8vaGVsaW8taW5mb3JtYXRpY3Mub3JnL0FSX05PQUFTV1BDT2JzZXJ2ZXJfMjAyNDA1MTVfMDI0ODM1X05PQUExMzY3OF8yMDI0MDUxNQ__", - "AR--NOAA_SWPC_Observer--aXZvOi8vaGVsaW8taW5mb3JtYXRpY3Mub3JnL0FSX05PQUFTV1BDT2JzZXJ2ZXJfMjAyNDA1MTVfMDI0ODI2X05PQUExMzY3M18yMDI0MDUxNQ__", - "AR--NOAA_SWPC_Observer--aXZvOi8vaGVsaW8taW5mb3JtYXRpY3Mub3JnL0FSX05PQUFTV1BDT2JzZXJ2ZXJfMjAyNDA1MTVfMDI0ODM4X05PQUExMzY3OV8yMDI0MDUxNQ__", - "AR--NOAA_SWPC_Observer--aXZvOi8vaGVsaW8taW5mb3JtYXRpY3Mub3JnL0FSX05PQUFTV1BDT2JzZXJ2ZXJfMjAyNDA1MTVfMDI0ODI4X05PQUExMzY3NF8yMDI0MDUxNQ__", - "AR--NOAA_SWPC_Observer--aXZvOi8vaGVsaW8taW5mb3JtYXRpY3Mub3JnL0FSX05PQUFTV1BDT2JzZXJ2ZXJfMjAyNDA1MTVfMDI0ODMwX05PQUExMzY3NV8yMDI0MDUxNQ__", - "AR--NOAA_SWPC_Observer--aXZvOi8vaGVsaW8taW5mb3JtYXRpY3Mub3JnL0FSX05PQUFTV1BDT2JzZXJ2ZXJfMjAyNDA1MTVfMDI0ODMzX05PQUExMzY3Nl8yMDI0MDUxNQ__" - ] + "date": 1715731311000, + "centerX": -3018.5704096094664, + "centerY": -410.28075595668, + "imageScale": 38.72705408, + "event_selections": [ + "CCMC>>DONKI>>CME", + "RHESSI>>Solar Flares" + ], + "event_visibility_selections": { + "HEK": { + "marker_visibility": false, + "label_visibility": false }, - { - "frms": [ - "EGSO_SFC" - ], - "open": 1, - "event_type": "SS", - "event_instances": [] - } - ], - "visible": true, - "labels_visible": false, - "markers_visible": false, - "layer_available_visible": false - }, - "tree_CCMC": { - "id": "CCMC", - "layers": [ - { - "frms": [ - "CME" - ], - "open": 1, - "event_type": "C3", - "event_instances": [] - } - ], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": false - }, - "tree_RHESSI": { - "id": "RHESSI", - "layers": [ - { - "frms": [ - "all" - ], - "open": 1, - "event_type": "F2", - "event_instances": [] - } - ], - "visible": true, - "labels_visible": false, - "markers_visible": true, - "layer_available_visible": true - } - }, - "imageLayers": [ - { - "opacity": 100, - "visible": true, - "diffTime": 1, - "uiLabels": [ - { - "name": "SDO", - "label": "Observatory" + "CCMC": { + "marker_visibility": true, + "label_visibility": true }, - { - "name": "AIA", - "label": "Instrument" + "RHESSI": { + "marker_visibility": true, + "label_visibility": false }, + "WSA": { + "marker_visibility": true, + "label_visibility": true + } + }, + "imageLayers": [ { - "name": "1600", - "label": "Measurement" + "opacity": 100, + "visible": true, + "diffTime": 1, + "uiLabels": [ + { + "name": "SDO", + "label": "Observatory" + }, + { + "name": "AIA", + "label": "Instrument" + }, + { + "name": "1600", + "label": "Measurement" + } + ], + "diffCount": 60, + "Instrument": "AIA", + "difference": 0, + "Measurement": "1600", + "Observatory": "SDO", + "baseDiffTime": "2024-06-17T10:49:02.000Z" } - ], - "diffCount": 60, - "Instrument": "AIA", - "difference": 0, - "Measurement": "1600", - "Observatory": "SDO", - "baseDiffTime": "2024-06-17T10:49:02.000Z" - } - ], - "celestialBodies": { - "soho": [ - "soho-mercury-tree-label", - "soho-mars-tree-label", - "soho-jupiter-tree-label", - "soho-uranus-tree-label" ], - "stereo_a": [ - "stereo_a-mercury-tree-label", - "stereo_a-venus-tree-label", - "stereo_a-earth-tree-label", - "stereo_a-mars-tree-label", - "stereo_a-jupiter-tree-label", - "stereo_a-saturn-tree-label", - "stereo_a-uranus-tree-label", - "stereo_a-neptune-tree-label", - "stereo_a-psp-tree-branch" - ], - "stereo_b": [ - "stereo_b-mercury-tree-label", - "stereo_b-earth-tree-label", - "stereo_b-mars-tree-label", - "stereo_b-jupiter-tree-label", - "stereo_b-saturn-tree-label" - ] - } + "celestialBodies": { + "soho": [ + "soho-mercury-tree-label", + "soho-mars-tree-label", + "soho-jupiter-tree-label", + "soho-uranus-tree-label" + ], + "stereo_a": [ + "stereo_a-mercury-tree-label", + "stereo_a-venus-tree-label", + "stereo_a-earth-tree-label", + "stereo_a-mars-tree-label", + "stereo_a-jupiter-tree-label", + "stereo_a-saturn-tree-label", + "stereo_a-uranus-tree-label", + "stereo_a-neptune-tree-label", + "stereo_a-psp-tree-branch" + ], + "stereo_b": [ + "stereo_b-mercury-tree-label", + "stereo_b-earth-tree-label", + "stereo_b-mars-tree-label", + "stereo_b-jupiter-tree-label", + "stereo_b-saturn-tree-label" + ] + } } diff --git a/tests/unit_tests/validation/test_data/client_state/valid/valid_12.json b/tests/unit_tests/validation/test_data/client_state/valid/valid_12.json index 9dbe23a26..78af2879b 100644 --- a/tests/unit_tests/validation/test_data/client_state/valid/valid_12.json +++ b/tests/unit_tests/validation/test_data/client_state/valid/valid_12.json @@ -1,145 +1,104 @@ { - "date": 1712557812000, - "centerX": -172.3873528481749, - "centerY": -216.25766746329495, - "imageScale": 0.60511022, - "eventLayers": { - "tree_CCMC": { - "id": "CCMC", - "labels_visible": true, - "layer_available_visible": true, - "layers": [ - { - "event_instances": [], - "event_type": "AR", - "frms": [ - "NOAA_SWPC_Observer" - ], - "open": true + "date": 1712557812000, + "centerX": -172.3873528481749, + "centerY": -216.25766746329495, + "imageScale": 0.60511022, + "event_selections": [], + "event_visibility_selections": { + "HEK": { + "marker_visibility": true, + "label_visibility": true }, - { - "event_instances": [], - "event_type": "FL", - "frms": [ - "SWPC" - ], - "open": true - } - ], - "markers_visible": true, - "visible": true - }, - "tree_HEK": { - "id": "HEK", - "labels_visible": true, - "layer_available_visible": true, - "layers": [], - "markers_visible": true, - "visible": true - }, - "tree_RHESSI": { - "id": "RHESSI", - "labels_visible": true, - "layer_available_visible": true, - "layers": [ - { - "event_instances": [], - "event_type": "AR", - "frms": [ - "NOAA_SWPC_Observer" - ], - "open": true - }, - { - "event_instances": [], - "event_type": "FL", - "frms": [ - "SWPC" - ], - "open": true - } - ], - "markers_visible": true, - "visible": true - } - }, - "imageLayers": [ - { - "end": "2024-04-08 06:30:13", - "start": "2024-04-08 06:19:24", - "opacity": 35, - "visible": true, - "diffTime": 1, - "nickname": "IRIS SJI 2796", - "sourceId": 89, - "uiLabels": [ - { - "name": "IRIS", - "label": "Observatory" + "CCMC": { + "marker_visibility": true, + "label_visibility": true }, - { - "name": "SJI", - "label": "Instrument" + "RHESSI": { + "marker_visibility": true, + "label_visibility": true }, - { - "name": "2796", - "label": "Measurement" + "WSA": { + "marker_visibility": true, + "label_visibility": true } - ], - "diffCount": 60, - "Instrument": "SJI", - "difference": 0, - "Measurement": "2796", - "Observatory": "IRIS", - "baseDiffTime": "2024-06-12T08:32:57.000Z", - "layeringOrder": 1 }, - { - "end": "2024-06-11 06:38:14", - "start": "2012-07-05 00:09:05", - "opacity": 100, - "visible": "1", - "diffTime": 1, - "nickname": "AIA 1600", - "sourceId": 15, - "uiLabels": [ + "imageLayers": [ { - "name": "SDO", - "label": "Observatory" + "end": "2024-04-08 06:30:13", + "start": "2024-04-08 06:19:24", + "opacity": 35, + "visible": true, + "diffTime": 1, + "nickname": "IRIS SJI 2796", + "sourceId": 89, + "uiLabels": [ + { + "name": "IRIS", + "label": "Observatory" + }, + { + "name": "SJI", + "label": "Instrument" + }, + { + "name": "2796", + "label": "Measurement" + } + ], + "diffCount": 60, + "Instrument": "SJI", + "difference": 0, + "Measurement": "2796", + "Observatory": "IRIS", + "baseDiffTime": "2024-06-12T08:32:57.000Z", + "layeringOrder": 1 }, { - "name": "AIA", - "label": "Instrument" - }, - { - "name": "1600", - "label": "Measurement" + "end": "2024-06-11 06:38:14", + "start": "2012-07-05 00:09:05", + "opacity": 100, + "visible": "1", + "diffTime": 1, + "nickname": "AIA 1600", + "sourceId": 15, + "uiLabels": [ + { + "name": "SDO", + "label": "Observatory" + }, + { + "name": "AIA", + "label": "Instrument" + }, + { + "name": "1600", + "label": "Measurement" + } + ], + "diffCount": 60, + "Instrument": "AIA", + "difference": 0, + "Measurement": "1600", + "Observatory": "SDO", + "baseDiffTime": "2024-04-08T05:30:13.000Z", + "layeringOrder": 1 } - ], - "diffCount": 60, - "Instrument": "AIA", - "difference": 0, - "Measurement": "1600", - "Observatory": "SDO", - "baseDiffTime": "2024-04-08T05:30:13.000Z", - "layeringOrder": 1 - } - ], - "celestialBodies": { - "soho": [ - "soho-mercury-tree-label", - "soho-venus-tree-label", - "soho-mars-tree-label", - "soho-jupiter-tree-label", - "soho-saturn-tree-label", - "soho-uranus-tree-label", - "soho-neptune-tree-label" ], - "stereo_a": [ - "stereo_a-mercury-tree-label" - ], - "stereo_b": [ - "stereo_b-mercury-tree-label" - ] - } + "celestialBodies": { + "soho": [ + "soho-mercury-tree-label", + "soho-venus-tree-label", + "soho-mars-tree-label", + "soho-jupiter-tree-label", + "soho-saturn-tree-label", + "soho-uranus-tree-label", + "soho-neptune-tree-label" + ], + "stereo_a": [ + "stereo_a-mercury-tree-label" + ], + "stereo_b": [ + "stereo_b-mercury-tree-label" + ] + } } diff --git a/tests/unit_tests/validation/test_data/client_state/valid/valid_13.json b/tests/unit_tests/validation/test_data/client_state/valid/valid_13.json index 73f203d4a..850bd3146 100644 --- a/tests/unit_tests/validation/test_data/client_state/valid/valid_13.json +++ b/tests/unit_tests/validation/test_data/client_state/valid/valid_13.json @@ -1,145 +1,104 @@ { - "date": 1712557812000, - "centerX": -172.3873528481749, - "centerY": -216.25766746329495, - "imageScale": 0.60511022, - "eventLayers": { - "tree_CCMC": { - "id": "CCMC", - "labels_visible": true, - "layer_available_visible": true, - "layers": [ - { - "event_instances": [], - "event_type": "AR", - "frms": [ - "NOAA_SWPC_Observer" - ], - "open": true + "date": 1712557812000, + "centerX": -172.3873528481749, + "centerY": -216.25766746329495, + "imageScale": 0.60511022, + "event_selections": [], + "event_visibility_selections": { + "HEK": { + "marker_visibility": true, + "label_visibility": true }, - { - "event_instances": [], - "event_type": "FL", - "frms": [ - "SWPC" - ], - "open": true - } - ], - "markers_visible": true, - "visible": true - }, - "tree_HEK": { - "id": "HEK", - "labels_visible": true, - "layer_available_visible": true, - "layers": [], - "markers_visible": true, - "visible": true - }, - "tree_RHESSI": { - "id": "RHESSI", - "labels_visible": true, - "layer_available_visible": true, - "layers": [ - { - "event_instances": [], - "event_type": "AR", - "frms": [ - "NOAA_SWPC_Observer" - ], - "open": true - }, - { - "event_instances": [], - "event_type": "FL", - "frms": [ - "SWPC" - ], - "open": true - } - ], - "markers_visible": true, - "visible": true - } - }, - "imageLayers": [ - { - "end": "2024-04-08 06:30:13", - "start": "2024-04-08 06:19:24", - "opacity": 35, - "visible": true, - "diffTime": 1, - "nickname": "IRIS SJI 2796", - "sourceId": 89, - "uiLabels": [ - { - "name": "IRIS", - "label": "Observatory" + "CCMC": { + "marker_visibility": true, + "label_visibility": true }, - { - "name": "SJI", - "label": "Instrument" + "RHESSI": { + "marker_visibility": true, + "label_visibility": true }, - { - "name": "2796", - "label": "Measurement" + "WSA": { + "marker_visibility": true, + "label_visibility": true } - ], - "diffCount": 60, - "Instrument": "SJI", - "difference": 0, - "Measurement": "2796", - "Observatory": "IRIS", - "baseDiffTime": "2024-06-12T08:32:57.000Z", - "layeringOrder": 1 }, - { - "end": "2024-06-11 06:38:14", - "start": "2012-07-05 00:09:05", - "opacity": "100", - "visible": "1", - "diffTime": 1, - "nickname": "AIA 1600", - "sourceId": 15, - "uiLabels": [ + "imageLayers": [ { - "name": "SDO", - "label": "Observatory" + "end": "2024-04-08 06:30:13", + "start": "2024-04-08 06:19:24", + "opacity": 35, + "visible": true, + "diffTime": 1, + "nickname": "IRIS SJI 2796", + "sourceId": 89, + "uiLabels": [ + { + "name": "IRIS", + "label": "Observatory" + }, + { + "name": "SJI", + "label": "Instrument" + }, + { + "name": "2796", + "label": "Measurement" + } + ], + "diffCount": 60, + "Instrument": "SJI", + "difference": 0, + "Measurement": "2796", + "Observatory": "IRIS", + "baseDiffTime": "2024-06-12T08:32:57.000Z", + "layeringOrder": 1 }, { - "name": "AIA", - "label": "Instrument" - }, - { - "name": "1600", - "label": "Measurement" + "end": "2024-06-11 06:38:14", + "start": "2012-07-05 00:09:05", + "opacity": "100", + "visible": "1", + "diffTime": 1, + "nickname": "AIA 1600", + "sourceId": 15, + "uiLabels": [ + { + "name": "SDO", + "label": "Observatory" + }, + { + "name": "AIA", + "label": "Instrument" + }, + { + "name": "1600", + "label": "Measurement" + } + ], + "diffCount": 60, + "Instrument": "AIA", + "difference": 0, + "Measurement": "1600", + "Observatory": "SDO", + "baseDiffTime": "2024-04-08T05:30:13.000Z", + "layeringOrder": 1 } - ], - "diffCount": 60, - "Instrument": "AIA", - "difference": 0, - "Measurement": "1600", - "Observatory": "SDO", - "baseDiffTime": "2024-04-08T05:30:13.000Z", - "layeringOrder": 1 - } - ], - "celestialBodies": { - "soho": [ - "soho-mercury-tree-label", - "soho-venus-tree-label", - "soho-mars-tree-label", - "soho-jupiter-tree-label", - "soho-saturn-tree-label", - "soho-uranus-tree-label", - "soho-neptune-tree-label" ], - "stereo_a": [ - "stereo_a-mercury-tree-label" - ], - "stereo_b": [ - "stereo_b-mercury-tree-label" - ] - } + "celestialBodies": { + "soho": [ + "soho-mercury-tree-label", + "soho-venus-tree-label", + "soho-mars-tree-label", + "soho-jupiter-tree-label", + "soho-saturn-tree-label", + "soho-uranus-tree-label", + "soho-neptune-tree-label" + ], + "stereo_a": [ + "stereo_a-mercury-tree-label" + ], + "stereo_b": [ + "stereo_b-mercury-tree-label" + ] + } } diff --git a/tests/unit_tests/validation/test_data/client_state/valid/valid_14.json b/tests/unit_tests/validation/test_data/client_state/valid/valid_14.json index 7d541aa0c..9a70be043 100644 --- a/tests/unit_tests/validation/test_data/client_state/valid/valid_14.json +++ b/tests/unit_tests/validation/test_data/client_state/valid/valid_14.json @@ -1,145 +1,104 @@ { - "date": 1712557812000, - "centerX": -172.3873528481749, - "centerY": -216.25766746329495, - "imageScale": 0.60511022, - "eventLayers": { - "tree_CCMC": { - "id": "CCMC", - "labels_visible": true, - "layer_available_visible": true, - "layers": [ - { - "event_instances": [], - "event_type": "AR", - "frms": [ - "NOAA_SWPC_Observer" - ], - "open": true + "date": 1712557812000, + "centerX": -172.3873528481749, + "centerY": -216.25766746329495, + "imageScale": 0.60511022, + "event_selections": [], + "event_visibility_selections": { + "HEK": { + "marker_visibility": true, + "label_visibility": true }, - { - "event_instances": [], - "event_type": "FL", - "frms": [ - "SWPC" - ], - "open": true - } - ], - "markers_visible": true, - "visible": true - }, - "tree_HEK": { - "id": "HEK", - "labels_visible": true, - "layer_available_visible": true, - "layers": [], - "markers_visible": true, - "visible": true - }, - "tree_RHESSI": { - "id": "RHESSI", - "labels_visible": true, - "layer_available_visible": true, - "layers": [ - { - "event_instances": [], - "event_type": "AR", - "frms": [ - "NOAA_SWPC_Observer" - ], - "open": true - }, - { - "event_instances": [], - "event_type": "FL", - "frms": [ - "SWPC" - ], - "open": true - } - ], - "markers_visible": true, - "visible": true - } - }, - "imageLayers": [ - { - "end": "2024-04-08 06:30:13", - "start": "2024-04-08 06:19:24", - "opacity": 35, - "visible": true, - "diffTime": 1, - "nickname": "IRIS SJI 2796", - "sourceId": 89, - "uiLabels": [ - { - "name": "IRIS", - "label": "" + "CCMC": { + "marker_visibility": true, + "label_visibility": true }, - { - "name": "SJI", - "label": "Instrument" + "RHESSI": { + "marker_visibility": true, + "label_visibility": true }, - { - "name": "2796", - "label": "" + "WSA": { + "marker_visibility": true, + "label_visibility": true } - ], - "diffCount": 60, - "Instrument": "SJI", - "difference": 0, - "Measurement": "2796", - "Observatory": "IRIS", - "baseDiffTime": "2024-06-12T08:32:57.000Z", - "layeringOrder": 1 }, - { - "end": "2024-06-11 06:38:14", - "start": "2012-07-05 00:09:05", - "opacity": "100", - "visible": "1", - "diffTime": 1, - "nickname": "AIA 1600", - "sourceId": 15, - "uiLabels": [ + "imageLayers": [ { - "name": "SDO", - "label": "" + "end": "2024-04-08 06:30:13", + "start": "2024-04-08 06:19:24", + "opacity": 35, + "visible": true, + "diffTime": 1, + "nickname": "IRIS SJI 2796", + "sourceId": 89, + "uiLabels": [ + { + "name": "IRIS", + "label": "" + }, + { + "name": "SJI", + "label": "Instrument" + }, + { + "name": "2796", + "label": "" + } + ], + "diffCount": 60, + "Instrument": "SJI", + "difference": 0, + "Measurement": "2796", + "Observatory": "IRIS", + "baseDiffTime": "2024-06-12T08:32:57.000Z", + "layeringOrder": 1 }, { - "name": "AIA", - "label": "" - }, - { - "name": "1600", - "label": "" + "end": "2024-06-11 06:38:14", + "start": "2012-07-05 00:09:05", + "opacity": "100", + "visible": "1", + "diffTime": 1, + "nickname": "AIA 1600", + "sourceId": 15, + "uiLabels": [ + { + "name": "SDO", + "label": "" + }, + { + "name": "AIA", + "label": "" + }, + { + "name": "1600", + "label": "" + } + ], + "diffCount": 60, + "Instrument": "AIA", + "difference": 0, + "Measurement": "1600", + "Observatory": "SDO", + "baseDiffTime": "2024-04-08T05:30:13.000Z", + "layeringOrder": 1 } - ], - "diffCount": 60, - "Instrument": "AIA", - "difference": 0, - "Measurement": "1600", - "Observatory": "SDO", - "baseDiffTime": "2024-04-08T05:30:13.000Z", - "layeringOrder": 1 - } - ], - "celestialBodies": { - "soho": [ - "soho-mercury-tree-label", - "soho-venus-tree-label", - "soho-mars-tree-label", - "soho-jupiter-tree-label", - "soho-saturn-tree-label", - "soho-uranus-tree-label", - "soho-neptune-tree-label" ], - "stereo_a": [ - "stereo_a-mercury-tree-label" - ], - "stereo_b": [ - "stereo_b-mercury-tree-label" - ] - } + "celestialBodies": { + "soho": [ + "soho-mercury-tree-label", + "soho-venus-tree-label", + "soho-mars-tree-label", + "soho-jupiter-tree-label", + "soho-saturn-tree-label", + "soho-uranus-tree-label", + "soho-neptune-tree-label" + ], + "stereo_a": [ + "stereo_a-mercury-tree-label" + ], + "stereo_b": [ + "stereo_b-mercury-tree-label" + ] + } } diff --git a/tests/unit_tests/validation/test_data/client_state/valid/valid_15.json b/tests/unit_tests/validation/test_data/client_state/valid/valid_15.json index 7d541aa0c..9a70be043 100644 --- a/tests/unit_tests/validation/test_data/client_state/valid/valid_15.json +++ b/tests/unit_tests/validation/test_data/client_state/valid/valid_15.json @@ -1,145 +1,104 @@ { - "date": 1712557812000, - "centerX": -172.3873528481749, - "centerY": -216.25766746329495, - "imageScale": 0.60511022, - "eventLayers": { - "tree_CCMC": { - "id": "CCMC", - "labels_visible": true, - "layer_available_visible": true, - "layers": [ - { - "event_instances": [], - "event_type": "AR", - "frms": [ - "NOAA_SWPC_Observer" - ], - "open": true + "date": 1712557812000, + "centerX": -172.3873528481749, + "centerY": -216.25766746329495, + "imageScale": 0.60511022, + "event_selections": [], + "event_visibility_selections": { + "HEK": { + "marker_visibility": true, + "label_visibility": true }, - { - "event_instances": [], - "event_type": "FL", - "frms": [ - "SWPC" - ], - "open": true - } - ], - "markers_visible": true, - "visible": true - }, - "tree_HEK": { - "id": "HEK", - "labels_visible": true, - "layer_available_visible": true, - "layers": [], - "markers_visible": true, - "visible": true - }, - "tree_RHESSI": { - "id": "RHESSI", - "labels_visible": true, - "layer_available_visible": true, - "layers": [ - { - "event_instances": [], - "event_type": "AR", - "frms": [ - "NOAA_SWPC_Observer" - ], - "open": true - }, - { - "event_instances": [], - "event_type": "FL", - "frms": [ - "SWPC" - ], - "open": true - } - ], - "markers_visible": true, - "visible": true - } - }, - "imageLayers": [ - { - "end": "2024-04-08 06:30:13", - "start": "2024-04-08 06:19:24", - "opacity": 35, - "visible": true, - "diffTime": 1, - "nickname": "IRIS SJI 2796", - "sourceId": 89, - "uiLabels": [ - { - "name": "IRIS", - "label": "" + "CCMC": { + "marker_visibility": true, + "label_visibility": true }, - { - "name": "SJI", - "label": "Instrument" + "RHESSI": { + "marker_visibility": true, + "label_visibility": true }, - { - "name": "2796", - "label": "" + "WSA": { + "marker_visibility": true, + "label_visibility": true } - ], - "diffCount": 60, - "Instrument": "SJI", - "difference": 0, - "Measurement": "2796", - "Observatory": "IRIS", - "baseDiffTime": "2024-06-12T08:32:57.000Z", - "layeringOrder": 1 }, - { - "end": "2024-06-11 06:38:14", - "start": "2012-07-05 00:09:05", - "opacity": "100", - "visible": "1", - "diffTime": 1, - "nickname": "AIA 1600", - "sourceId": 15, - "uiLabels": [ + "imageLayers": [ { - "name": "SDO", - "label": "" + "end": "2024-04-08 06:30:13", + "start": "2024-04-08 06:19:24", + "opacity": 35, + "visible": true, + "diffTime": 1, + "nickname": "IRIS SJI 2796", + "sourceId": 89, + "uiLabels": [ + { + "name": "IRIS", + "label": "" + }, + { + "name": "SJI", + "label": "Instrument" + }, + { + "name": "2796", + "label": "" + } + ], + "diffCount": 60, + "Instrument": "SJI", + "difference": 0, + "Measurement": "2796", + "Observatory": "IRIS", + "baseDiffTime": "2024-06-12T08:32:57.000Z", + "layeringOrder": 1 }, { - "name": "AIA", - "label": "" - }, - { - "name": "1600", - "label": "" + "end": "2024-06-11 06:38:14", + "start": "2012-07-05 00:09:05", + "opacity": "100", + "visible": "1", + "diffTime": 1, + "nickname": "AIA 1600", + "sourceId": 15, + "uiLabels": [ + { + "name": "SDO", + "label": "" + }, + { + "name": "AIA", + "label": "" + }, + { + "name": "1600", + "label": "" + } + ], + "diffCount": 60, + "Instrument": "AIA", + "difference": 0, + "Measurement": "1600", + "Observatory": "SDO", + "baseDiffTime": "2024-04-08T05:30:13.000Z", + "layeringOrder": 1 } - ], - "diffCount": 60, - "Instrument": "AIA", - "difference": 0, - "Measurement": "1600", - "Observatory": "SDO", - "baseDiffTime": "2024-04-08T05:30:13.000Z", - "layeringOrder": 1 - } - ], - "celestialBodies": { - "soho": [ - "soho-mercury-tree-label", - "soho-venus-tree-label", - "soho-mars-tree-label", - "soho-jupiter-tree-label", - "soho-saturn-tree-label", - "soho-uranus-tree-label", - "soho-neptune-tree-label" ], - "stereo_a": [ - "stereo_a-mercury-tree-label" - ], - "stereo_b": [ - "stereo_b-mercury-tree-label" - ] - } + "celestialBodies": { + "soho": [ + "soho-mercury-tree-label", + "soho-venus-tree-label", + "soho-mars-tree-label", + "soho-jupiter-tree-label", + "soho-saturn-tree-label", + "soho-uranus-tree-label", + "soho-neptune-tree-label" + ], + "stereo_a": [ + "stereo_a-mercury-tree-label" + ], + "stereo_b": [ + "stereo_b-mercury-tree-label" + ] + } } diff --git a/tests/unit_tests/validation/test_data/client_state/valid/valid_16.json b/tests/unit_tests/validation/test_data/client_state/valid/valid_16.json index 87d11227a..27ad82c29 100644 --- a/tests/unit_tests/validation/test_data/client_state/valid/valid_16.json +++ b/tests/unit_tests/validation/test_data/client_state/valid/valid_16.json @@ -1,95 +1,82 @@ { - "date": 1697979187000, - "imageScale": 4.84088176, - "centerX": 100.29816701545585, - "centerY": 1064.2094221854543, - "imageLayers": [ - { - "uiLabels": [ + "date": 1697979187000, + "imageScale": 4.84088176, + "centerX": 100.29816701545585, + "centerY": 1064.2094221854543, + "imageLayers": [ { - "label": "Observatory", - "name": "SDO" + "uiLabels": [ + { + "label": "Observatory", + "name": "SDO" + }, + { + "label": "Instrument", + "name": "AIA" + }, + { + "label": "Measurement", + "name": "131" + } + ], + "Observatory": "SDO", + "Instrument": "AIA", + "Measurement": "131", + "visible": "1", + "opacity": 100, + "difference": 0, + "diffCount": 60, + "diffTime": 1, + "baseDiffTime": "2018-03-30T04:18:36.000Z", + "sourceId": 9, + "nickname": "AIA 131", + "layeringOrder": 1, + "start": "2010-06-02 00:05:35", + "end": "2024-07-22 15:48:07" + } + ], + "event_selections": [ + "HEK>>CME>>CACTus_\\(Computer_Aided_CME_Tracking\\)", + "HEK>>CME>>CACTus \\(Computer Aided CME Tracking\\)" + ], + "event_visibility_selections": { + "HEK": { + "marker_visibility": true, + "label_visibility": true }, - { - "label": "Instrument", - "name": "AIA" + "CCMC": { + "marker_visibility": true, + "label_visibility": true }, - { - "label": "Measurement", - "name": "131" - } - ], - "Observatory": "SDO", - "Instrument": "AIA", - "Measurement": "131", - "visible": "1", - "opacity": 100, - "difference": 0, - "diffCount": 60, - "diffTime": 1, - "baseDiffTime": "2018-03-30T04:18:36.000Z", - "sourceId": 9, - "nickname": "AIA 131", - "layeringOrder": 1, - "start": "2010-06-02 00:05:35", - "end": "2024-07-22 15:48:07" - } - ], - "eventLayers": { - "tree_HEK": { - "id": "HEK", - "layers": [ - { - "event_type": "CE", - "frms": [ - "CACTus_\\(Computer_Aided_CME_Tracking\\)" - ], - "event_instances": [], - "open": 1 + "RHESSI": { + "marker_visibility": true, + "label_visibility": true + }, + "WSA": { + "marker_visibility": true, + "label_visibility": true } - ], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": false }, - "tree_CCMC": { - "id": "CCMC", - "layers": [], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": true - }, - "tree_RHESSI": { - "id": "RHESSI", - "layers": [], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": true + "celestialBodies": { + "soho": [ + "soho-mercury-tree-label", + "soho-venus-tree-label", + "soho-mars-tree-label", + "soho-jupiter-tree-label", + "soho-saturn-tree-label", + "soho-uranus-tree-label", + "soho-neptune-tree-label" + ], + "stereo_a": [], + "stereo_b": [ + "stereo_b-mercury-tree-label", + "stereo_b-venus-tree-label", + "stereo_b-earth-tree-label", + "stereo_b-mars-tree-label", + "stereo_b-jupiter-tree-label", + "stereo_b-saturn-tree-label", + "stereo_b-uranus-tree-label", + "stereo_b-neptune-tree-label" + ] } - }, - "celestialBodies": { - "soho": [ - "soho-mercury-tree-label", - "soho-venus-tree-label", - "soho-mars-tree-label", - "soho-jupiter-tree-label", - "soho-saturn-tree-label", - "soho-uranus-tree-label", - "soho-neptune-tree-label" - ], - "stereo_a": [], - "stereo_b": [ - "stereo_b-mercury-tree-label", - "stereo_b-venus-tree-label", - "stereo_b-earth-tree-label", - "stereo_b-mars-tree-label", - "stereo_b-jupiter-tree-label", - "stereo_b-saturn-tree-label", - "stereo_b-uranus-tree-label", - "stereo_b-neptune-tree-label" - ] - } } diff --git a/tests/unit_tests/validation/test_data/client_state/valid/valid_17.json b/tests/unit_tests/validation/test_data/client_state/valid/valid_17.json index 6053161fd..1afc866bd 100644 --- a/tests/unit_tests/validation/test_data/client_state/valid/valid_17.json +++ b/tests/unit_tests/validation/test_data/client_state/valid/valid_17.json @@ -1,259 +1,97 @@ { - "date": 1410269529000, - "imageScale": 4.84088176, - "centerX": -2894.0322215830834, - "centerY": 101.72638697583727, - "imageLayers": [ - { - "end": "2024-07-29 17:33:45", - "start": "2010-06-02 00:05:36", - "opacity": 100, - "visible": true, - "diffTime": 1, - "nickname": "AIA 171", - "sourceId": 10, - "uiLabels": [ - { - "label": "Observatory", - "name": "SDO" - }, - { - "label": "Instrument", - "name": "AIA" - }, - { - "label": "Measurement", - "name": "171" + "date": 1410269529000, + "imageScale": 4.84088176, + "centerX": -2894.0322215830834, + "centerY": 101.72638697583727, + "imageLayers": [ + { + "end": "2024-07-29 17:33:45", + "start": "2010-06-02 00:05:36", + "opacity": 100, + "visible": true, + "diffTime": 1, + "nickname": "AIA 171", + "sourceId": 10, + "uiLabels": [ + { + "label": "Observatory", + "name": "SDO" + }, + { + "label": "Instrument", + "name": "AIA" + }, + { + "label": "Measurement", + "name": "171" + } + ], + "diffCount": 60, + "Instrument": "AIA", + "difference": 0, + "Measurement": "171", + "Observatory": "SDO", + "baseDiffTime": "2024-07-19T13:28:50.000Z", + "layeringOrder": 1 } - ], - "diffCount": 60, - "Instrument": "AIA", - "difference": 0, - "Measurement": "171", - "Observatory": "SDO", - "baseDiffTime": "2024-07-19T13:28:50.000Z", - "layeringOrder": 1 - } - ], - "eventLayers": { - "tree_HEK": { - "id": "HEK", - "layers": [ - { - "event_type": "AR", - "frms": [ - "HMI_SHARP", - "NOAA_SWPC_Observer", - "SPoCA" - ], - "event_instances": [], - "open": 1 - }, - { - "event_type": "CC", - "frms": [ - "all" - ], - "event_instances": [], - "open": 1 - }, - { - "event_type": "CD", - "frms": [ - "all" - ], - "event_instances": [], - "open": 1 - }, - { - "event_type": "CH", - "frms": [ - "SPoCA" - ], - "event_instances": [], - "open": 1 - }, - { - "event_type": "CJ", - "frms": [ - "all" - ], - "event_instances": [], - "open": 1 - }, - { - "event_type": "CE", - "frms": [ - "all" - ], - "event_instances": [], - "open": 1 - }, - { - "event_type": "CR", - "frms": [ - "all" - ], - "event_instances": [], - "open": 1 - }, - { - "event_type": "CW", - "frms": [ - "all" - ], - "event_instances": [], - "open": 1 - }, - { - "event_type": "EF", - "frms": [ - "Emerging_flux_region_module" - ], - "event_instances": [], - "open": 1 - }, - { - "event_type": "ER", - "frms": [ - "all" - ], - "event_instances": [], - "open": 1 - }, - { - "event_type": "FI", - "frms": [ - "all" - ], - "event_instances": [], - "open": 1 - }, - { - "event_type": "FA", - "frms": [ - "all" - ], - "event_instances": [], - "open": 1 - }, - { - "event_type": "FE", - "frms": [ - "all" - ], - "event_instances": [], - "open": 1 - }, - { - "event_type": "FL", - "frms": [ - "all" - ], - "event_instances": [], - "open": 1 - }, - { - "event_type": "LP", - "frms": [ - "all" - ], - "event_instances": [], - "open": 1 - }, - { - "event_type": "OS", - "frms": [ - "all" - ], - "event_instances": [], - "open": 1 - }, - { - "event_type": "PG", - "frms": [ - "all" - ], - "event_instances": [], - "open": 1 - }, - { - "event_type": "SG", - "frms": [ - "Sigmoid_Sniffer" - ], - "event_instances": [], - "open": 1 - }, - { - "event_type": "SP", - "frms": [ - "all" - ], - "event_instances": [], - "open": 1 - }, - { - "event_type": "SS", - "frms": [ - "EGSO_SFC" - ], - "event_instances": [], - "open": 1 - }, - { - "event_type": "TO", - "frms": [ - "SSW_PFSS_v2_\\+_null_point_finder_v20180808" - ], - "event_instances": [], - "open": 1 - } - ], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": true - }, - "tree_CCMC": { - "id": "CCMC", - "layers": [ - { - "event_type": "C3", - "frms": [ - "CME" - ], - "event_instances": [], - "open": 1 - }, - { - "event_type": "FP", - "frms": [ - "MAG4_LoS_FEr" - ], - "event_instances": [], - "open": 1 + ], + "event_selections": [ + "HEK>>Active Region>>HMI_SHARP", + "HEK>>Active Region>>HMI SHARP", + "HEK>>Active Region>>NOAA_SWPC_Observer", + "HEK>>Active Region>>NOAA SWPC Observer", + "HEK>>Active Region>>SPoCA", + "HEK>>Coronal Cavity", + "HEK>>Coronal Dimming", + "HEK>>Coronal Hole>>SPoCA", + "HEK>>Coronal Jet", + "HEK>>CME", + "HEK>>Coronal Rain", + "HEK>>Coronal Wave", + "HEK>>Emerging Flux>>Emerging_flux_region_module", + "HEK>>Emerging Flux>>Emerging flux region module", + "HEK>>Eruption", + "HEK>>Filament", + "HEK>>Filament Activation", + "HEK>>Filament Eruption", + "HEK>>Flare", + "HEK>>Loop", + "HEK>>Oscillation", + "HEK>>Plage", + "HEK>>Sigmoid>>Sigmoid_Sniffer", + "HEK>>Sigmoid>>Sigmoid Sniffer", + "HEK>>Spray Surge", + "HEK>>Sunspot>>EGSO_SFC", + "HEK>>Sunspot>>EGSO SFC", + "HEK>>Topological Object>>SSW_PFSS_v2_\\+_null_point_finder_v20180808", + "HEK>>Topological Object>>SSW PFSS v2 \\+ null point finder v20180808", + "CCMC>>DONKI>>CME", + "CCMC>>Solar Flare Predictions>>MAG4_LoS_FEr", + "CCMC>>Solar Flare Predictions>>MAG4 LoS FEr" + ], + "event_visibility_selections": { + "HEK": { + "marker_visibility": true, + "label_visibility": true + }, + "CCMC": { + "marker_visibility": true, + "label_visibility": true + }, + "RHESSI": { + "marker_visibility": true, + "label_visibility": true + }, + "WSA": { + "marker_visibility": true, + "label_visibility": true } - ], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": true }, - "tree_RHESSI": { - "id": "RHESSI", - "layers": [], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": true + "celestialBodies": { + "soho": [], + "stereo_a": [ + "stereo_a-mercury-tree-label" + ], + "stereo_b": [] } - }, - "celestialBodies": { - "soho": [], - "stereo_a": [ - "stereo_a-mercury-tree-label" - ], - "stereo_b": [] - } } diff --git a/tests/unit_tests/validation/test_data/client_state/valid/valid_2.json b/tests/unit_tests/validation/test_data/client_state/valid/valid_2.json index cf0ce8032..76fc152f4 100644 --- a/tests/unit_tests/validation/test_data/client_state/valid/valid_2.json +++ b/tests/unit_tests/validation/test_data/client_state/valid/valid_2.json @@ -1,116 +1,109 @@ { - "date": 1718087894000, - "centerX": -2401.07735296, - "centerY": -1316.71983872, - "imageScale": 77.45410816, - "eventLayers": { - "tree_HEK": { - "id": "HEK", - "layers": [], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": false - }, - "tree_CCMC": { - "id": "CCMC", - "layers": [], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": true - }, - "tree_RHESSI": { - "id": "RHESSI", - "layers": [], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": true - } - }, - "imageLayers": [ - { - "end": "2024-04-08 06:30:13", - "start": "2024-04-08 06:19:24", - "opacity": 35, - "visible": true, - "diffTime": 1, - "nickname": "IRIS SJI 2796", - "sourceId": 89, - "uiLabels": [ - { - "name": "IRIS", - "label": "Observatory" + "date": 1718087894000, + "centerX": -2401.07735296, + "centerY": -1316.71983872, + "imageScale": 77.45410816, + "event_selections": [], + "event_visibility_selections": { + "HEK": { + "marker_visibility": true, + "label_visibility": true }, - { - "name": "SJI", - "label": "Instrument" + "CCMC": { + "marker_visibility": true, + "label_visibility": true }, - { - "name": "2796", - "label": "Measurement" + "RHESSI": { + "marker_visibility": true, + "label_visibility": true + }, + "WSA": { + "marker_visibility": true, + "label_visibility": true } - ], - "diffCount": 60, - "Instrument": "SJI", - "difference": 0, - "Measurement": "2796", - "Observatory": "IRIS", - "baseDiffTime": "2024-06-12T08:32:57.000Z", - "layeringOrder": 1 }, - { - "end": "2024-06-11 06:38:14", - "start": "2012-07-05 00:09:05", - "opacity": 100, - "visible": "1", - "diffTime": 1, - "nickname": "AIA 1600", - "sourceId": 15, - "uiLabels": [ - { - "name": "SDO", - "label": "Observatory" - }, + "imageLayers": [ { - "name": "AIA", - "label": "Instrument" + "end": "2024-04-08 06:30:13", + "start": "2024-04-08 06:19:24", + "opacity": 35, + "visible": true, + "diffTime": 1, + "nickname": "IRIS SJI 2796", + "sourceId": 89, + "uiLabels": [ + { + "name": "IRIS", + "label": "Observatory" + }, + { + "name": "SJI", + "label": "Instrument" + }, + { + "name": "2796", + "label": "Measurement" + } + ], + "diffCount": 60, + "Instrument": "SJI", + "difference": 0, + "Measurement": "2796", + "Observatory": "IRIS", + "baseDiffTime": "2024-06-12T08:32:57.000Z", + "layeringOrder": 1 }, { - "name": "1600", - "label": "Measurement" + "end": "2024-06-11 06:38:14", + "start": "2012-07-05 00:09:05", + "opacity": 100, + "visible": "1", + "diffTime": 1, + "nickname": "AIA 1600", + "sourceId": 15, + "uiLabels": [ + { + "name": "SDO", + "label": "Observatory" + }, + { + "name": "AIA", + "label": "Instrument" + }, + { + "name": "1600", + "label": "Measurement" + } + ], + "diffCount": 60, + "Instrument": "AIA", + "difference": 0, + "Measurement": "1600", + "Observatory": "SDO", + "baseDiffTime": "2024-04-08T05:30:13.000Z", + "layeringOrder": 1 } - ], - "diffCount": 60, - "Instrument": "AIA", - "difference": 0, - "Measurement": "1600", - "Observatory": "SDO", - "baseDiffTime": "2024-04-08T05:30:13.000Z", - "layeringOrder": 1 - } - ], - "celestialBodies": { - "soho": [ - "soho-mercury-tree-label", - "soho-mars-tree-label", - "soho-jupiter-tree-label", - "soho-saturn-tree-label", - "soho-uranus-tree-label", - "soho-neptune-tree-label" - ], - "stereo_a": [ - "stereo_a-mercury-tree-label", - "stereo_a-earth-tree-label", - "stereo_a-mars-tree-label", - "stereo_a-jupiter-tree-label", - "stereo_a-saturn-tree-label", - "stereo_a-uranus-tree-label", - "stereo_a-psp-tree-branch" ], - "stereo_b": [ - "stereo_b-mercury-tree-label" - ] - } + "celestialBodies": { + "soho": [ + "soho-mercury-tree-label", + "soho-mars-tree-label", + "soho-jupiter-tree-label", + "soho-saturn-tree-label", + "soho-uranus-tree-label", + "soho-neptune-tree-label" + ], + "stereo_a": [ + "stereo_a-mercury-tree-label", + "stereo_a-earth-tree-label", + "stereo_a-mars-tree-label", + "stereo_a-jupiter-tree-label", + "stereo_a-saturn-tree-label", + "stereo_a-uranus-tree-label", + "stereo_a-psp-tree-branch" + ], + "stereo_b": [ + "stereo_b-mercury-tree-label" + ] + } } diff --git a/tests/unit_tests/validation/test_data/client_state/valid/valid_3.json b/tests/unit_tests/validation/test_data/client_state/valid/valid_3.json index 56bb5a6bb..7a0b4d622 100644 --- a/tests/unit_tests/validation/test_data/client_state/valid/valid_3.json +++ b/tests/unit_tests/validation/test_data/client_state/valid/valid_3.json @@ -1,133 +1,114 @@ { - "date": 1718087894000, - "centerX": -2401.07735296, - "centerY": -1316.71983872, - "imageScale": 77.45410816, - "eventLayers": { - "tree_HEK": { - "id": "HEK", - "layers": [ - { - "frms": [ - "NOAA_SWPC_Observer" - ], - "open": 1, - "event_type": "AR", - "event_instances": [] + "date": 1718087894000, + "centerX": -2401.07735296, + "centerY": -1316.71983872, + "imageScale": 77.45410816, + "event_selections": [ + "HEK>>Active Region>>NOAA_SWPC_Observer", + "HEK>>Active Region>>NOAA SWPC Observer", + "HEK>>Sunspot>>EGSO_SFC", + "HEK>>Sunspot>>EGSO SFC" + ], + "event_visibility_selections": { + "HEK": { + "marker_visibility": true, + "label_visibility": true }, - { - "frms": [ - "EGSO_SFC" - ], - "open": 1, - "event_type": "SS", - "event_instances": [] - } - ], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": false - }, - "tree_CCMC": { - "id": "CCMC", - "layers": [], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": true - }, - "tree_RHESSI": { - "id": "RHESSI", - "layers": [], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": true - } - }, - "imageLayers": [ - { - "end": "2024-04-08 06:30:13", - "start": "2024-04-08 06:19:24", - "opacity": 35, - "visible": true, - "diffTime": 1, - "nickname": "IRIS SJI 2796", - "sourceId": 89, - "uiLabels": [ - { - "name": "IRIS", - "label": "Observatory" + "CCMC": { + "marker_visibility": true, + "label_visibility": true }, - { - "name": "SJI", - "label": "Instrument" + "RHESSI": { + "marker_visibility": true, + "label_visibility": true }, - { - "name": "2796", - "label": "Measurement" + "WSA": { + "marker_visibility": true, + "label_visibility": true } - ], - "diffCount": 60, - "Instrument": "SJI", - "difference": 0, - "Measurement": "2796", - "Observatory": "IRIS", - "baseDiffTime": "2024-06-12T08:32:57.000Z", - "layeringOrder": 1 }, - { - "end": "2024-06-11 06:38:14", - "start": "2012-07-05 00:09:05", - "opacity": 100, - "visible": "1", - "diffTime": 1, - "nickname": "AIA 1600", - "sourceId": 15, - "uiLabels": [ - { - "name": "SDO", - "label": "Observatory" - }, + "imageLayers": [ { - "name": "AIA", - "label": "Instrument" + "end": "2024-04-08 06:30:13", + "start": "2024-04-08 06:19:24", + "opacity": 35, + "visible": true, + "diffTime": 1, + "nickname": "IRIS SJI 2796", + "sourceId": 89, + "uiLabels": [ + { + "name": "IRIS", + "label": "Observatory" + }, + { + "name": "SJI", + "label": "Instrument" + }, + { + "name": "2796", + "label": "Measurement" + } + ], + "diffCount": 60, + "Instrument": "SJI", + "difference": 0, + "Measurement": "2796", + "Observatory": "IRIS", + "baseDiffTime": "2024-06-12T08:32:57.000Z", + "layeringOrder": 1 }, { - "name": "1600", - "label": "Measurement" + "end": "2024-06-11 06:38:14", + "start": "2012-07-05 00:09:05", + "opacity": 100, + "visible": "1", + "diffTime": 1, + "nickname": "AIA 1600", + "sourceId": 15, + "uiLabels": [ + { + "name": "SDO", + "label": "Observatory" + }, + { + "name": "AIA", + "label": "Instrument" + }, + { + "name": "1600", + "label": "Measurement" + } + ], + "diffCount": 60, + "Instrument": "AIA", + "difference": 0, + "Measurement": "1600", + "Observatory": "SDO", + "baseDiffTime": "2024-04-08T05:30:13.000Z", + "layeringOrder": 1 } - ], - "diffCount": 60, - "Instrument": "AIA", - "difference": 0, - "Measurement": "1600", - "Observatory": "SDO", - "baseDiffTime": "2024-04-08T05:30:13.000Z", - "layeringOrder": 1 - } - ], - "celestialBodies": { - "soho": [ - "soho-mercury-tree-label", - "soho-mars-tree-label", - "soho-jupiter-tree-label", - "soho-saturn-tree-label", - "soho-uranus-tree-label", - "soho-neptune-tree-label" - ], - "stereo_a": [ - "stereo_a-mercury-tree-label", - "stereo_a-earth-tree-label", - "stereo_a-mars-tree-label", - "stereo_a-jupiter-tree-label", - "stereo_a-saturn-tree-label", - "stereo_a-uranus-tree-label", - "stereo_a-psp-tree-branch" ], - "stereo_b": [ - "stereo_b-mercury-tree-label" - ] - } + "celestialBodies": { + "soho": [ + "soho-mercury-tree-label", + "soho-mars-tree-label", + "soho-jupiter-tree-label", + "soho-saturn-tree-label", + "soho-uranus-tree-label", + "soho-neptune-tree-label" + ], + "stereo_a": [ + "stereo_a-mercury-tree-label", + "stereo_a-earth-tree-label", + "stereo_a-mars-tree-label", + "stereo_a-jupiter-tree-label", + "stereo_a-saturn-tree-label", + "stereo_a-uranus-tree-label", + "stereo_a-psp-tree-branch" + ], + "stereo_b": [ + "stereo_b-mercury-tree-label" + ] + } } diff --git a/tests/unit_tests/validation/test_data/client_state/valid/valid_4.json b/tests/unit_tests/validation/test_data/client_state/valid/valid_4.json index af6718e5b..ec6a40df6 100644 --- a/tests/unit_tests/validation/test_data/client_state/valid/valid_4.json +++ b/tests/unit_tests/validation/test_data/client_state/valid/valid_4.json @@ -1,153 +1,117 @@ { - "date": 1718087894000, - "centerX": 3950.15951616, - "centerY": 4724.70059776, - "imageScale": 77.45410816, - "eventLayers": { - "tree_HEK": { - "id": "HEK", - "layers": [ - { - "frms": [ - "NOAA_SWPC_Observer" - ], - "open": 1, - "event_type": "AR", - "event_instances": [] + "date": 1718087894000, + "centerX": 3950.15951616, + "centerY": 4724.70059776, + "imageScale": 77.45410816, + "event_selections": [ + "HEK>>Active Region>>NOAA_SWPC_Observer", + "HEK>>Active Region>>NOAA SWPC Observer", + "HEK>>Sunspot>>EGSO_SFC", + "HEK>>Sunspot>>EGSO SFC", + "CCMC>>DONKI>>CME", + "CCMC>>Solar Flare Predictions>>ASAP" + ], + "event_visibility_selections": { + "HEK": { + "marker_visibility": true, + "label_visibility": true }, - { - "frms": [ - "EGSO_SFC" - ], - "open": 1, - "event_type": "SS", - "event_instances": [] - } - ], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": false - }, - "tree_CCMC": { - "id": "CCMC", - "layers": [ - { - "frms": [ - "CME" - ], - "open": 1, - "event_type": "C3", - "event_instances": [] + "CCMC": { + "marker_visibility": true, + "label_visibility": true }, - { - "frms": [], - "open": 1, - "event_type": "FP", - "event_instances": [ - "FP--ASAP--MWFhNTE2ZWQ5YWY0NWExNzJiZDM2ZGQzZDVkMDYyODgwZTNmYzIyNDQ1MmE5Zjg0ZTUzY2I0MTZjN2VkZDc0NA__", - "FP--ASAP--NWNmODQ3NzdhMGE1NTg5NGIyMjhjMzliNmQxMzk3M2U5OGQ0MjY1MDMwMTViZGEzMDU3NTkxMjU1NDBmZGUwNA__", - "FP--ASAP--MTFmMThkYmZjNzFlYTBmNDAzNjYyYTEzNTFhNzE4ODIyYTNlZWMwY2FlZTBkYjk0ZTg4MGYxMjcwNjEyZDBjYw__" - ] - } - ], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": true - }, - "tree_RHESSI": { - "id": "RHESSI", - "layers": [], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": true - } - }, - "imageLayers": [ - { - "end": "2024-04-08 06:30:13", - "start": "2024-04-08 06:19:24", - "opacity": 35, - "visible": true, - "diffTime": 1, - "nickname": "IRIS SJI 2796", - "sourceId": 89, - "uiLabels": [ - { - "name": "IRIS", - "label": "Observatory" - }, - { - "name": "SJI", - "label": "Instrument" + "RHESSI": { + "marker_visibility": true, + "label_visibility": true }, - { - "name": "2796", - "label": "Measurement" + "WSA": { + "marker_visibility": true, + "label_visibility": true } - ], - "diffCount": 60, - "Instrument": "SJI", - "difference": 0, - "Measurement": "2796", - "Observatory": "IRIS", - "baseDiffTime": "2024-06-12T08:32:57.000Z", - "layeringOrder": 1 }, - { - "end": "2024-06-11 06:38:14", - "start": "2012-07-05 00:09:05", - "opacity": 100, - "visible": "1", - "diffTime": 1, - "nickname": "AIA 1600", - "sourceId": 15, - "uiLabels": [ + "imageLayers": [ { - "name": "SDO", - "label": "Observatory" + "end": "2024-04-08 06:30:13", + "start": "2024-04-08 06:19:24", + "opacity": 35, + "visible": true, + "diffTime": 1, + "nickname": "IRIS SJI 2796", + "sourceId": 89, + "uiLabels": [ + { + "name": "IRIS", + "label": "Observatory" + }, + { + "name": "SJI", + "label": "Instrument" + }, + { + "name": "2796", + "label": "Measurement" + } + ], + "diffCount": 60, + "Instrument": "SJI", + "difference": 0, + "Measurement": "2796", + "Observatory": "IRIS", + "baseDiffTime": "2024-06-12T08:32:57.000Z", + "layeringOrder": 1 }, { - "name": "AIA", - "label": "Instrument" - }, - { - "name": "1600", - "label": "Measurement" + "end": "2024-06-11 06:38:14", + "start": "2012-07-05 00:09:05", + "opacity": 100, + "visible": "1", + "diffTime": 1, + "nickname": "AIA 1600", + "sourceId": 15, + "uiLabels": [ + { + "name": "SDO", + "label": "Observatory" + }, + { + "name": "AIA", + "label": "Instrument" + }, + { + "name": "1600", + "label": "Measurement" + } + ], + "diffCount": 60, + "Instrument": "AIA", + "difference": 0, + "Measurement": "1600", + "Observatory": "SDO", + "baseDiffTime": "2024-04-08T05:30:13.000Z", + "layeringOrder": 1 } - ], - "diffCount": 60, - "Instrument": "AIA", - "difference": 0, - "Measurement": "1600", - "Observatory": "SDO", - "baseDiffTime": "2024-04-08T05:30:13.000Z", - "layeringOrder": 1 - } - ], - "celestialBodies": { - "soho": [ - "soho-mars-tree-label", - "soho-jupiter-tree-label" ], - "stereo_a": [ - "stereo_a-mercury-tree-label", - "stereo_a-venus-tree-label", - "stereo_a-earth-tree-label", - "stereo_a-mars-tree-label", - "stereo_a-jupiter-tree-label", - "stereo_a-saturn-tree-label", - "stereo_a-uranus-tree-label", - "stereo_a-neptune-tree-label", - "stereo_a-psp-tree-branch" - ], - "stereo_b": [ - "stereo_b-mercury-tree-label", - "stereo_b-mars-tree-label", - "stereo_b-jupiter-tree-label", - "stereo_b-saturn-tree-label" - ] - } + "celestialBodies": { + "soho": [ + "soho-mars-tree-label", + "soho-jupiter-tree-label" + ], + "stereo_a": [ + "stereo_a-mercury-tree-label", + "stereo_a-venus-tree-label", + "stereo_a-earth-tree-label", + "stereo_a-mars-tree-label", + "stereo_a-jupiter-tree-label", + "stereo_a-saturn-tree-label", + "stereo_a-uranus-tree-label", + "stereo_a-neptune-tree-label", + "stereo_a-psp-tree-branch" + ], + "stereo_b": [ + "stereo_b-mercury-tree-label", + "stereo_b-mars-tree-label", + "stereo_b-jupiter-tree-label", + "stereo_b-saturn-tree-label" + ] + } } diff --git a/tests/unit_tests/validation/test_data/client_state/valid/valid_5.json b/tests/unit_tests/validation/test_data/client_state/valid/valid_5.json index a78d21d2a..d3c39801c 100644 --- a/tests/unit_tests/validation/test_data/client_state/valid/valid_5.json +++ b/tests/unit_tests/validation/test_data/client_state/valid/valid_5.json @@ -1,155 +1,119 @@ { - "date": 1718087894000, - "centerX": 1471.6280550400002, - "centerY": 2168.71502848, - "imageScale": 77.45410816, - "eventLayers": { - "tree_HEK": { - "id": "HEK", - "layers": [ - { - "frms": [ - "NOAA_SWPC_Observer" - ], - "open": 1, - "event_type": "AR", - "event_instances": [] + "date": 1718087894000, + "centerX": 1471.6280550400002, + "centerY": 2168.71502848, + "imageScale": 77.45410816, + "event_selections": [ + "HEK>>Active Region>>NOAA_SWPC_Observer", + "HEK>>Active Region>>NOAA SWPC Observer", + "HEK>>Sunspot>>EGSO_SFC", + "HEK>>Sunspot>>EGSO SFC", + "CCMC>>DONKI>>CME", + "CCMC>>Solar Flare Predictions>>ASAP" + ], + "event_visibility_selections": { + "HEK": { + "marker_visibility": true, + "label_visibility": true }, - { - "frms": [ - "EGSO_SFC" - ], - "open": 1, - "event_type": "SS", - "event_instances": [] - } - ], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": false - }, - "tree_CCMC": { - "id": "CCMC", - "layers": [ - { - "frms": [ - "CME" - ], - "open": 1, - "event_type": "C3", - "event_instances": [] + "CCMC": { + "marker_visibility": true, + "label_visibility": true }, - { - "frms": [], - "open": 1, - "event_type": "FP", - "event_instances": [ - "FP--ASAP--MWFhNTE2ZWQ5YWY0NWExNzJiZDM2ZGQzZDVkMDYyODgwZTNmYzIyNDQ1MmE5Zjg0ZTUzY2I0MTZjN2VkZDc0NA__", - "FP--ASAP--NWNmODQ3NzdhMGE1NTg5NGIyMjhjMzliNmQxMzk3M2U5OGQ0MjY1MDMwMTViZGEzMDU3NTkxMjU1NDBmZGUwNA__", - "FP--ASAP--MTFmMThkYmZjNzFlYTBmNDAzNjYyYTEzNTFhNzE4ODIyYTNlZWMwY2FlZTBkYjk0ZTg4MGYxMjcwNjEyZDBjYw__" - ] - } - ], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": true - }, - "tree_RHESSI": { - "id": "RHESSI", - "layers": [], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": true - } - }, - "imageLayers": [ - { - "end": "2024-04-08 06:30:13", - "start": "2024-04-08 06:19:24", - "opacity": 35, - "visible": true, - "diffTime": 1, - "nickname": "IRIS SJI 2796", - "sourceId": 89, - "uiLabels": [ - { - "name": "IRIS", - "label": "Observatory" - }, - { - "name": "SJI", - "label": "Instrument" + "RHESSI": { + "marker_visibility": true, + "label_visibility": true }, - { - "name": "2796", - "label": "Measurement" + "WSA": { + "marker_visibility": true, + "label_visibility": true } - ], - "diffCount": 60, - "Instrument": "SJI", - "difference": 0, - "Measurement": "2796", - "Observatory": "IRIS", - "baseDiffTime": "2024-06-12T08:32:57.000Z", - "layeringOrder": 1 }, - { - "end": "2024-06-11 06:38:14", - "start": "2012-07-05 00:09:05", - "opacity": 100, - "visible": "1", - "diffTime": 1, - "nickname": "AIA 1600", - "sourceId": 15, - "uiLabels": [ + "imageLayers": [ { - "name": "SDO", - "label": "Observatory" + "end": "2024-04-08 06:30:13", + "start": "2024-04-08 06:19:24", + "opacity": 35, + "visible": true, + "diffTime": 1, + "nickname": "IRIS SJI 2796", + "sourceId": 89, + "uiLabels": [ + { + "name": "IRIS", + "label": "Observatory" + }, + { + "name": "SJI", + "label": "Instrument" + }, + { + "name": "2796", + "label": "Measurement" + } + ], + "diffCount": 60, + "Instrument": "SJI", + "difference": 0, + "Measurement": "2796", + "Observatory": "IRIS", + "baseDiffTime": "2024-06-12T08:32:57.000Z", + "layeringOrder": 1 }, { - "name": "AIA", - "label": "Instrument" - }, - { - "name": "1600", - "label": "Measurement" + "end": "2024-06-11 06:38:14", + "start": "2012-07-05 00:09:05", + "opacity": 100, + "visible": "1", + "diffTime": 1, + "nickname": "AIA 1600", + "sourceId": 15, + "uiLabels": [ + { + "name": "SDO", + "label": "Observatory" + }, + { + "name": "AIA", + "label": "Instrument" + }, + { + "name": "1600", + "label": "Measurement" + } + ], + "diffCount": 60, + "Instrument": "AIA", + "difference": 0, + "Measurement": "1600", + "Observatory": "SDO", + "baseDiffTime": "2024-04-08T05:30:13.000Z", + "layeringOrder": 1 } - ], - "diffCount": 60, - "Instrument": "AIA", - "difference": 0, - "Measurement": "1600", - "Observatory": "SDO", - "baseDiffTime": "2024-04-08T05:30:13.000Z", - "layeringOrder": 1 - } - ], - "celestialBodies": { - "soho": [ - "soho-mercury-tree-label", - "soho-mars-tree-label", - "soho-jupiter-tree-label", - "soho-uranus-tree-label" ], - "stereo_a": [ - "stereo_a-mercury-tree-label", - "stereo_a-venus-tree-label", - "stereo_a-earth-tree-label", - "stereo_a-mars-tree-label", - "stereo_a-jupiter-tree-label", - "stereo_a-saturn-tree-label", - "stereo_a-uranus-tree-label", - "stereo_a-neptune-tree-label", - "stereo_a-psp-tree-branch" - ], - "stereo_b": [ - "stereo_b-mercury-tree-label", - "stereo_b-mars-tree-label", - "stereo_b-jupiter-tree-label", - "stereo_b-saturn-tree-label" - ] - } + "celestialBodies": { + "soho": [ + "soho-mercury-tree-label", + "soho-mars-tree-label", + "soho-jupiter-tree-label", + "soho-uranus-tree-label" + ], + "stereo_a": [ + "stereo_a-mercury-tree-label", + "stereo_a-venus-tree-label", + "stereo_a-earth-tree-label", + "stereo_a-mars-tree-label", + "stereo_a-jupiter-tree-label", + "stereo_a-saturn-tree-label", + "stereo_a-uranus-tree-label", + "stereo_a-neptune-tree-label", + "stereo_a-psp-tree-branch" + ], + "stereo_b": [ + "stereo_b-mercury-tree-label", + "stereo_b-mars-tree-label", + "stereo_b-jupiter-tree-label", + "stereo_b-saturn-tree-label" + ] + } } diff --git a/tests/unit_tests/validation/test_data/client_state/valid/valid_6.json b/tests/unit_tests/validation/test_data/client_state/valid/valid_6.json index 758da4a3e..bde9b97f5 100644 --- a/tests/unit_tests/validation/test_data/client_state/valid/valid_6.json +++ b/tests/unit_tests/validation/test_data/client_state/valid/valid_6.json @@ -1,120 +1,84 @@ { - "date": 1718087894000, - "centerX": 1471.6280550400002, - "centerY": 2168.71502848, - "imageScale": 77.45410816, - "eventLayers": { - "tree_HEK": { - "id": "HEK", - "layers": [ - { - "frms": [ - "NOAA_SWPC_Observer" - ], - "open": 1, - "event_type": "AR", - "event_instances": [] + "date": 1718087894000, + "centerX": 1471.6280550400002, + "centerY": 2168.71502848, + "imageScale": 77.45410816, + "event_selections": [ + "HEK>>Active Region>>NOAA_SWPC_Observer", + "HEK>>Active Region>>NOAA SWPC Observer", + "HEK>>Sunspot>>EGSO_SFC", + "HEK>>Sunspot>>EGSO SFC", + "CCMC>>DONKI>>CME", + "CCMC>>Solar Flare Predictions>>ASAP" + ], + "event_visibility_selections": { + "HEK": { + "marker_visibility": true, + "label_visibility": true }, - { - "frms": [ - "EGSO_SFC" - ], - "open": 1, - "event_type": "SS", - "event_instances": [] - } - ], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": false - }, - "tree_CCMC": { - "id": "CCMC", - "layers": [ - { - "frms": [ - "CME" - ], - "open": 1, - "event_type": "C3", - "event_instances": [] + "CCMC": { + "marker_visibility": true, + "label_visibility": true }, - { - "frms": [], - "open": 1, - "event_type": "FP", - "event_instances": [ - "FP--ASAP--MWFhNTE2ZWQ5YWY0NWExNzJiZDM2ZGQzZDVkMDYyODgwZTNmYzIyNDQ1MmE5Zjg0ZTUzY2I0MTZjN2VkZDc0NA__", - "FP--ASAP--NWNmODQ3NzdhMGE1NTg5NGIyMjhjMzliNmQxMzk3M2U5OGQ0MjY1MDMwMTViZGEzMDU3NTkxMjU1NDBmZGUwNA__", - "FP--ASAP--MTFmMThkYmZjNzFlYTBmNDAzNjYyYTEzNTFhNzE4ODIyYTNlZWMwY2FlZTBkYjk0ZTg4MGYxMjcwNjEyZDBjYw__" - ] + "RHESSI": { + "marker_visibility": true, + "label_visibility": true + }, + "WSA": { + "marker_visibility": true, + "label_visibility": true } - ], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": true }, - "tree_RHESSI": { - "id": "RHESSI", - "layers": [], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": true - } - }, - "imageLayers": [ - { - "opacity": 100, - "visible": true, - "diffTime": 1, - "uiLabels": [ - { - "name": "SDO", - "label": "Observatory" - }, - { - "name": "AIA", - "label": "Instrument" - }, + "imageLayers": [ { - "name": "1600", - "label": "Measurement" + "opacity": 100, + "visible": true, + "diffTime": 1, + "uiLabels": [ + { + "name": "SDO", + "label": "Observatory" + }, + { + "name": "AIA", + "label": "Instrument" + }, + { + "name": "1600", + "label": "Measurement" + } + ], + "diffCount": 60, + "Instrument": "AIA", + "difference": 0, + "Measurement": "1600", + "Observatory": "SDO", + "baseDiffTime": "2024-06-17T10:49:02.000Z" } - ], - "diffCount": 60, - "Instrument": "AIA", - "difference": 0, - "Measurement": "1600", - "Observatory": "SDO", - "baseDiffTime": "2024-06-17T10:49:02.000Z" - } - ], - "celestialBodies": { - "soho": [ - "soho-mercury-tree-label", - "soho-mars-tree-label", - "soho-jupiter-tree-label", - "soho-uranus-tree-label" ], - "stereo_a": [ - "stereo_a-mercury-tree-label", - "stereo_a-venus-tree-label", - "stereo_a-earth-tree-label", - "stereo_a-mars-tree-label", - "stereo_a-jupiter-tree-label", - "stereo_a-saturn-tree-label", - "stereo_a-uranus-tree-label", - "stereo_a-neptune-tree-label", - "stereo_a-psp-tree-branch" - ], - "stereo_b": [ - "stereo_b-mercury-tree-label", - "stereo_b-mars-tree-label", - "stereo_b-jupiter-tree-label", - "stereo_b-saturn-tree-label" - ] - } + "celestialBodies": { + "soho": [ + "soho-mercury-tree-label", + "soho-mars-tree-label", + "soho-jupiter-tree-label", + "soho-uranus-tree-label" + ], + "stereo_a": [ + "stereo_a-mercury-tree-label", + "stereo_a-venus-tree-label", + "stereo_a-earth-tree-label", + "stereo_a-mars-tree-label", + "stereo_a-jupiter-tree-label", + "stereo_a-saturn-tree-label", + "stereo_a-uranus-tree-label", + "stereo_a-neptune-tree-label", + "stereo_a-psp-tree-branch" + ], + "stereo_b": [ + "stereo_b-mercury-tree-label", + "stereo_b-mars-tree-label", + "stereo_b-jupiter-tree-label", + "stereo_b-saturn-tree-label" + ] + } } diff --git a/tests/unit_tests/validation/test_data/client_state/valid/valid_7.json b/tests/unit_tests/validation/test_data/client_state/valid/valid_7.json index d5a1fa0c7..81db2c5d3 100644 --- a/tests/unit_tests/validation/test_data/client_state/valid/valid_7.json +++ b/tests/unit_tests/validation/test_data/client_state/valid/valid_7.json @@ -1,102 +1,83 @@ { - "date": 1715731311000, - "centerX": 1471.6280550400002, - "centerY": 2168.71502848, - "imageScale": 77.45410816, - "eventLayers": { - "tree_HEK": { - "id": "HEK", - "layers": [ - { - "frms": [ - "NOAA_SWPC_Observer" - ], - "open": 1, - "event_type": "AR", - "event_instances": [] + "date": 1715731311000, + "centerX": 1471.6280550400002, + "centerY": 2168.71502848, + "imageScale": 77.45410816, + "event_selections": [ + "HEK>>Active Region>>NOAA_SWPC_Observer", + "HEK>>Active Region>>NOAA SWPC Observer", + "HEK>>Sunspot>>EGSO_SFC", + "HEK>>Sunspot>>EGSO SFC" + ], + "event_visibility_selections": { + "HEK": { + "marker_visibility": true, + "label_visibility": true }, - { - "frms": [ - "EGSO_SFC" - ], - "open": 1, - "event_type": "SS", - "event_instances": [] - } - ], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": false - }, - "tree_CCMC": { - "id": "CCMC", - "layers": [], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": true - }, - "tree_RHESSI": { - "id": "RHESSI", - "layers": [], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": true - } - }, - "imageLayers": [ - { - "opacity": 100, - "visible": true, - "diffTime": 1, - "uiLabels": [ - { - "name": "SDO", - "label": "Observatory" + "CCMC": { + "marker_visibility": true, + "label_visibility": true }, - { - "name": "AIA", - "label": "Instrument" + "RHESSI": { + "marker_visibility": true, + "label_visibility": true }, + "WSA": { + "marker_visibility": true, + "label_visibility": true + } + }, + "imageLayers": [ { - "name": "1600", - "label": "Measurement" + "opacity": 100, + "visible": true, + "diffTime": 1, + "uiLabels": [ + { + "name": "SDO", + "label": "Observatory" + }, + { + "name": "AIA", + "label": "Instrument" + }, + { + "name": "1600", + "label": "Measurement" + } + ], + "diffCount": 60, + "Instrument": "AIA", + "difference": 0, + "Measurement": "1600", + "Observatory": "SDO", + "baseDiffTime": "2024-06-17T10:49:02.000Z" } - ], - "diffCount": 60, - "Instrument": "AIA", - "difference": 0, - "Measurement": "1600", - "Observatory": "SDO", - "baseDiffTime": "2024-06-17T10:49:02.000Z" - } - ], - "celestialBodies": { - "soho": [ - "soho-mercury-tree-label", - "soho-mars-tree-label", - "soho-jupiter-tree-label", - "soho-uranus-tree-label" - ], - "stereo_a": [ - "stereo_a-mercury-tree-label", - "stereo_a-venus-tree-label", - "stereo_a-earth-tree-label", - "stereo_a-mars-tree-label", - "stereo_a-jupiter-tree-label", - "stereo_a-saturn-tree-label", - "stereo_a-uranus-tree-label", - "stereo_a-neptune-tree-label", - "stereo_a-psp-tree-branch" ], - "stereo_b": [ - "stereo_b-mercury-tree-label", - "stereo_b-earth-tree-label", - "stereo_b-mars-tree-label", - "stereo_b-jupiter-tree-label", - "stereo_b-saturn-tree-label" - ] - } + "celestialBodies": { + "soho": [ + "soho-mercury-tree-label", + "soho-mars-tree-label", + "soho-jupiter-tree-label", + "soho-uranus-tree-label" + ], + "stereo_a": [ + "stereo_a-mercury-tree-label", + "stereo_a-venus-tree-label", + "stereo_a-earth-tree-label", + "stereo_a-mars-tree-label", + "stereo_a-jupiter-tree-label", + "stereo_a-saturn-tree-label", + "stereo_a-uranus-tree-label", + "stereo_a-neptune-tree-label", + "stereo_a-psp-tree-branch" + ], + "stereo_b": [ + "stereo_b-mercury-tree-label", + "stereo_b-earth-tree-label", + "stereo_b-mars-tree-label", + "stereo_b-jupiter-tree-label", + "stereo_b-saturn-tree-label" + ] + } } diff --git a/tests/unit_tests/validation/test_data/client_state/valid/valid_8.json b/tests/unit_tests/validation/test_data/client_state/valid/valid_8.json index 291fbacd7..b9d3d47a4 100644 --- a/tests/unit_tests/validation/test_data/client_state/valid/valid_8.json +++ b/tests/unit_tests/validation/test_data/client_state/valid/valid_8.json @@ -1,111 +1,80 @@ { - "date": 1715731311000, - "centerX": -3018.5704096094664, - "centerY": -410.28075595668, - "imageScale": 38.72705408, - "eventLayers": { - "tree_HEK": { - "id": "HEK", - "layers": [ - { - "frms": [ - "NOAA_SWPC_Observer" - ], - "open": 1, - "event_type": "AR", - "event_instances": [] + "date": 1715731311000, + "centerX": -3018.5704096094664, + "centerY": -410.28075595668, + "imageScale": 38.72705408, + "event_selections": [ + "CCMC>>DONKI>>CME" + ], + "event_visibility_selections": { + "HEK": { + "marker_visibility": false, + "label_visibility": false }, - { - "frms": [ - "EGSO_SFC" - ], - "open": 1, - "event_type": "SS", - "event_instances": [] - } - ], - "visible": true, - "labels_visible": false, - "markers_visible": false, - "layer_available_visible": false - }, - "tree_CCMC": { - "id": "CCMC", - "layers": [ - { - "frms": [ - "CME" - ], - "open": 1, - "event_type": "C3", - "event_instances": [] - } - ], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": true - }, - "tree_RHESSI": { - "id": "RHESSI", - "layers": [], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": true - } - }, - "imageLayers": [ - { - "opacity": 100, - "visible": true, - "diffTime": 1, - "uiLabels": [ - { - "name": "SDO", - "label": "Observatory" + "CCMC": { + "marker_visibility": true, + "label_visibility": true }, - { - "name": "AIA", - "label": "Instrument" + "RHESSI": { + "marker_visibility": true, + "label_visibility": true }, + "WSA": { + "marker_visibility": true, + "label_visibility": true + } + }, + "imageLayers": [ { - "name": "1600", - "label": "Measurement" + "opacity": 100, + "visible": true, + "diffTime": 1, + "uiLabels": [ + { + "name": "SDO", + "label": "Observatory" + }, + { + "name": "AIA", + "label": "Instrument" + }, + { + "name": "1600", + "label": "Measurement" + } + ], + "diffCount": 60, + "Instrument": "AIA", + "difference": 0, + "Measurement": "1600", + "Observatory": "SDO", + "baseDiffTime": "2024-06-17T10:49:02.000Z" } - ], - "diffCount": 60, - "Instrument": "AIA", - "difference": 0, - "Measurement": "1600", - "Observatory": "SDO", - "baseDiffTime": "2024-06-17T10:49:02.000Z" - } - ], - "celestialBodies": { - "soho": [ - "soho-mercury-tree-label", - "soho-mars-tree-label", - "soho-jupiter-tree-label", - "soho-uranus-tree-label" ], - "stereo_a": [ - "stereo_a-mercury-tree-label", - "stereo_a-venus-tree-label", - "stereo_a-earth-tree-label", - "stereo_a-mars-tree-label", - "stereo_a-jupiter-tree-label", - "stereo_a-saturn-tree-label", - "stereo_a-uranus-tree-label", - "stereo_a-neptune-tree-label", - "stereo_a-psp-tree-branch" - ], - "stereo_b": [ - "stereo_b-mercury-tree-label", - "stereo_b-earth-tree-label", - "stereo_b-mars-tree-label", - "stereo_b-jupiter-tree-label", - "stereo_b-saturn-tree-label" - ] - } + "celestialBodies": { + "soho": [ + "soho-mercury-tree-label", + "soho-mars-tree-label", + "soho-jupiter-tree-label", + "soho-uranus-tree-label" + ], + "stereo_a": [ + "stereo_a-mercury-tree-label", + "stereo_a-venus-tree-label", + "stereo_a-earth-tree-label", + "stereo_a-mars-tree-label", + "stereo_a-jupiter-tree-label", + "stereo_a-saturn-tree-label", + "stereo_a-uranus-tree-label", + "stereo_a-neptune-tree-label", + "stereo_a-psp-tree-branch" + ], + "stereo_b": [ + "stereo_b-mercury-tree-label", + "stereo_b-earth-tree-label", + "stereo_b-mars-tree-label", + "stereo_b-jupiter-tree-label", + "stereo_b-saturn-tree-label" + ] + } } diff --git a/tests/unit_tests/validation/test_data/client_state/valid/valid_9.json b/tests/unit_tests/validation/test_data/client_state/valid/valid_9.json index 52c9d7cc7..b16542516 100644 --- a/tests/unit_tests/validation/test_data/client_state/valid/valid_9.json +++ b/tests/unit_tests/validation/test_data/client_state/valid/valid_9.json @@ -1,111 +1,80 @@ { - "date": 1715731311000, - "centerX": -3018.5704096094664, - "centerY": -410.28075595668, - "imageScale": 38.72705408, - "eventLayers": { - "tree_HEK": { - "id": "HEK", - "layers": [ - { - "frms": [ - "NOAA_SWPC_Observer" - ], - "open": 1, - "event_type": "AR", - "event_instances": [] + "date": 1715731311000, + "centerX": -3018.5704096094664, + "centerY": -410.28075595668, + "imageScale": 38.72705408, + "event_selections": [ + "CCMC>>DONKI>>CME" + ], + "event_visibility_selections": { + "HEK": { + "marker_visibility": false, + "label_visibility": false }, - { - "frms": [ - "EGSO_SFC" - ], - "open": 1, - "event_type": "SS", - "event_instances": [] - } - ], - "visible": true, - "labels_visible": false, - "markers_visible": false, - "layer_available_visible": false - }, - "tree_CCMC": { - "id": "CCMC", - "layers": [ - { - "frms": [ - "CME" - ], - "open": 1, - "event_type": "C3", - "event_instances": [] - } - ], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": false - }, - "tree_RHESSI": { - "id": "RHESSI", - "layers": [], - "visible": true, - "labels_visible": false, - "markers_visible": true, - "layer_available_visible": true - } - }, - "imageLayers": [ - { - "opacity": 100, - "visible": true, - "diffTime": 1, - "uiLabels": [ - { - "name": "SDO", - "label": "Observatory" + "CCMC": { + "marker_visibility": true, + "label_visibility": true }, - { - "name": "AIA", - "label": "Instrument" + "RHESSI": { + "marker_visibility": true, + "label_visibility": false }, + "WSA": { + "marker_visibility": true, + "label_visibility": true + } + }, + "imageLayers": [ { - "name": "1600", - "label": "Measurement" + "opacity": 100, + "visible": true, + "diffTime": 1, + "uiLabels": [ + { + "name": "SDO", + "label": "Observatory" + }, + { + "name": "AIA", + "label": "Instrument" + }, + { + "name": "1600", + "label": "Measurement" + } + ], + "diffCount": 60, + "Instrument": "AIA", + "difference": 0, + "Measurement": "1600", + "Observatory": "SDO", + "baseDiffTime": "2024-06-17T10:49:02.000Z" } - ], - "diffCount": 60, - "Instrument": "AIA", - "difference": 0, - "Measurement": "1600", - "Observatory": "SDO", - "baseDiffTime": "2024-06-17T10:49:02.000Z" - } - ], - "celestialBodies": { - "soho": [ - "soho-mercury-tree-label", - "soho-mars-tree-label", - "soho-jupiter-tree-label", - "soho-uranus-tree-label" ], - "stereo_a": [ - "stereo_a-mercury-tree-label", - "stereo_a-venus-tree-label", - "stereo_a-earth-tree-label", - "stereo_a-mars-tree-label", - "stereo_a-jupiter-tree-label", - "stereo_a-saturn-tree-label", - "stereo_a-uranus-tree-label", - "stereo_a-neptune-tree-label", - "stereo_a-psp-tree-branch" - ], - "stereo_b": [ - "stereo_b-mercury-tree-label", - "stereo_b-earth-tree-label", - "stereo_b-mars-tree-label", - "stereo_b-jupiter-tree-label", - "stereo_b-saturn-tree-label" - ] - } + "celestialBodies": { + "soho": [ + "soho-mercury-tree-label", + "soho-mars-tree-label", + "soho-jupiter-tree-label", + "soho-uranus-tree-label" + ], + "stereo_a": [ + "stereo_a-mercury-tree-label", + "stereo_a-venus-tree-label", + "stereo_a-earth-tree-label", + "stereo_a-mars-tree-label", + "stereo_a-jupiter-tree-label", + "stereo_a-saturn-tree-label", + "stereo_a-uranus-tree-label", + "stereo_a-neptune-tree-label", + "stereo_a-psp-tree-branch" + ], + "stereo_b": [ + "stereo_b-mercury-tree-label", + "stereo_b-earth-tree-label", + "stereo_b-mars-tree-label", + "stereo_b-jupiter-tree-label", + "stereo_b-saturn-tree-label" + ] + } } diff --git a/tests/unit_tests/validation/test_data/client_state/valid/valid_event_layer_name.json b/tests/unit_tests/validation/test_data/client_state/valid/valid_event_layer_name.json index ce07b2919..78af2879b 100644 --- a/tests/unit_tests/validation/test_data/client_state/valid/valid_event_layer_name.json +++ b/tests/unit_tests/validation/test_data/client_state/valid/valid_event_layer_name.json @@ -1,95 +1,104 @@ { - "date": 1712557812000, - "centerX": -172.3873528481749, - "centerY": -216.25766746329495, - "imageScale": 0.60511022, - "eventLayers": { - "allowed": { - "id": "HEK", - "layers": [], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": false - } - }, - "imageLayers": [ - { - "end": "2024-04-08 06:30:13", - "start": "2024-04-08 06:19:24", - "opacity": 35, - "visible": true, - "diffTime": 1, - "nickname": "IRIS SJI 2796", - "sourceId": 89, - "uiLabels": [ - { - "name": "IRIS", - "label": "Observatory" + "date": 1712557812000, + "centerX": -172.3873528481749, + "centerY": -216.25766746329495, + "imageScale": 0.60511022, + "event_selections": [], + "event_visibility_selections": { + "HEK": { + "marker_visibility": true, + "label_visibility": true }, - { - "name": "SJI", - "label": "Instrument" + "CCMC": { + "marker_visibility": true, + "label_visibility": true }, - { - "name": "2796", - "label": "Measurement" + "RHESSI": { + "marker_visibility": true, + "label_visibility": true + }, + "WSA": { + "marker_visibility": true, + "label_visibility": true } - ], - "diffCount": 60, - "Instrument": "SJI", - "difference": 0, - "Measurement": "2796", - "Observatory": "IRIS", - "baseDiffTime": "2024-06-12T08:32:57.000Z", - "layeringOrder": 1 }, - { - "end": "2024-06-11 06:38:14", - "start": "2012-07-05 00:09:05", - "opacity": 100, - "visible": "1", - "diffTime": 1, - "nickname": "AIA 1600", - "sourceId": 15, - "uiLabels": [ + "imageLayers": [ { - "name": "SDO", - "label": "Observatory" + "end": "2024-04-08 06:30:13", + "start": "2024-04-08 06:19:24", + "opacity": 35, + "visible": true, + "diffTime": 1, + "nickname": "IRIS SJI 2796", + "sourceId": 89, + "uiLabels": [ + { + "name": "IRIS", + "label": "Observatory" + }, + { + "name": "SJI", + "label": "Instrument" + }, + { + "name": "2796", + "label": "Measurement" + } + ], + "diffCount": 60, + "Instrument": "SJI", + "difference": 0, + "Measurement": "2796", + "Observatory": "IRIS", + "baseDiffTime": "2024-06-12T08:32:57.000Z", + "layeringOrder": 1 }, { - "name": "AIA", - "label": "Instrument" - }, - { - "name": "1600", - "label": "Measurement" + "end": "2024-06-11 06:38:14", + "start": "2012-07-05 00:09:05", + "opacity": 100, + "visible": "1", + "diffTime": 1, + "nickname": "AIA 1600", + "sourceId": 15, + "uiLabels": [ + { + "name": "SDO", + "label": "Observatory" + }, + { + "name": "AIA", + "label": "Instrument" + }, + { + "name": "1600", + "label": "Measurement" + } + ], + "diffCount": 60, + "Instrument": "AIA", + "difference": 0, + "Measurement": "1600", + "Observatory": "SDO", + "baseDiffTime": "2024-04-08T05:30:13.000Z", + "layeringOrder": 1 } - ], - "diffCount": 60, - "Instrument": "AIA", - "difference": 0, - "Measurement": "1600", - "Observatory": "SDO", - "baseDiffTime": "2024-04-08T05:30:13.000Z", - "layeringOrder": 1 - } - ], - "celestialBodies": { - "soho": [ - "soho-mercury-tree-label", - "soho-venus-tree-label", - "soho-mars-tree-label", - "soho-jupiter-tree-label", - "soho-saturn-tree-label", - "soho-uranus-tree-label", - "soho-neptune-tree-label" ], - "stereo_a": [ - "stereo_a-mercury-tree-label" - ], - "stereo_b": [ - "stereo_b-mercury-tree-label" - ] - } + "celestialBodies": { + "soho": [ + "soho-mercury-tree-label", + "soho-venus-tree-label", + "soho-mars-tree-label", + "soho-jupiter-tree-label", + "soho-saturn-tree-label", + "soho-uranus-tree-label", + "soho-neptune-tree-label" + ], + "stereo_a": [ + "stereo_a-mercury-tree-label" + ], + "stereo_b": [ + "stereo_b-mercury-tree-label" + ] + } } diff --git a/tests/unit_tests/validation/test_data/post_screenshot/valid/post_screenshot_1.json b/tests/unit_tests/validation/test_data/post_screenshot/valid/post_screenshot_1.json index 9eb250b8e..050e2075a 100644 --- a/tests/unit_tests/validation/test_data/post_screenshot/valid/post_screenshot_1.json +++ b/tests/unit_tests/validation/test_data/post_screenshot/valid/post_screenshot_1.json @@ -1,41 +1,6 @@ { "imageScale": 5.608481803348903, "layers": "[SDO,AIA,131,1,100,0,60,1,2018-03-30T04:18:36.000Z]", - "eventsState": { - "tree_HEK": { - "id": "HEK", - "layers": [ - { - "event_type": "CE", - "frms": [ - "CACTus_\\(Computer_Aided_CME_Tracking\\)" - ], - "event_instances": [], - "open": 1 - } - ], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": false - }, - "tree_CCMC": { - "id": "CCMC", - "layers": [], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": true - }, - "tree_RHESSI": { - "id": "RHESSI", - "layers": [], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": true - } - }, "scale": true, "scaleType": "earth", "scaleX": -2334, diff --git a/tests/unit_tests/validation/test_data/post_screenshot/valid/post_screenshot_punch.json b/tests/unit_tests/validation/test_data/post_screenshot/valid/post_screenshot_punch.json index 3b27a817c..037624e2c 100644 --- a/tests/unit_tests/validation/test_data/post_screenshot/valid/post_screenshot_punch.json +++ b/tests/unit_tests/validation/test_data/post_screenshot/valid/post_screenshot_punch.json @@ -1 +1 @@ -{"imageScale":210.11840895833043,"layers":"[PUNCH,WFI+NFI,Polarized Brightness,1,100,0,60,1,2026-04-22T14:59:57.000Z]","eventsState":{"tree_HEK":{"id":"HEK","visible":true,"markers_visible":true,"labels_visible":true,"layer_available_visible":true,"layers":[],"layers_v2":[]},"tree_CCMC":{"id":"CCMC","visible":true,"markers_visible":true,"labels_visible":true,"layer_available_visible":true,"layers":[],"layers_v2":[]},"tree_RHESSI":{"id":"RHESSI","visible":true,"markers_visible":true,"labels_visible":true,"layer_available_visible":true,"layers":[],"layers_v2":[]}},"scale":true,"scaleType":"earth","scaleX":28371,"scaleY":109542,"movieIcons":false,"date":"2026-04-22T15:59:57.497Z","display":false,"switchSources":false,"celestialBodiesLabels":"","celestialBodiesTrajectories":"","x1":-200172.4494534283,"x2":161231.21395490004,"y1":-126909.19775643574,"y2":133217.39253397734} +{"imageScale":210.11840895833043,"layers":"[PUNCH,WFI+NFI,Polarized Brightness,1,100,0,60,1,2026-04-22T14:59:57.000Z]","scale":true,"scaleType":"earth","scaleX":28371,"scaleY":109542,"movieIcons":false,"date":"2026-04-22T15:59:57.497Z","display":false,"switchSources":false,"celestialBodiesLabels":"","celestialBodiesTrajectories":"","x1":-200172.4494534283,"x2":161231.21395490004,"y1":-126909.19775643574,"y2":133217.39253397734} \ No newline at end of file diff --git a/tests/unit_tests/validation/test_data/post_screenshot/valid/post_screenshot_regression_1.json b/tests/unit_tests/validation/test_data/post_screenshot/valid/post_screenshot_regression_1.json index c16be4261..050e2075a 100644 --- a/tests/unit_tests/validation/test_data/post_screenshot/valid/post_screenshot_regression_1.json +++ b/tests/unit_tests/validation/test_data/post_screenshot/valid/post_screenshot_regression_1.json @@ -1,50 +1,6 @@ { "imageScale": 5.608481803348903, "layers": "[SDO,AIA,131,1,100,0,60,1,2018-03-30T04:18:36.000Z]", - "eventsState": { - "tree_HEK": { - "id": "HEK", - "layers": [ - { - "event_type": "AR", - "frms": [ - "NOAA_SWPC_Observer" - ], - "event_instances": [], - "open": 1 - }, - { - "event_type": "CE", - "frms": [], - "event_instances": [ - "CE--CACTus_\\(Computer_Aided_CME_Tracking\\)--aXZvOi8vaGVsaW8taW5mb3JtYXRpY3Mub3JnL0NFX0NBQ1R1cyhDb21wdXRlckFpZGVkQ01FVHJhY2tpbmcpXzIwMjUwMzMwXzAyMTMyMl8yMDgyLjE3", - "CE--CACTus_\\(Computer_Aided_CME_Tracking\\)--aXZvOi8vaGVsaW8taW5mb3JtYXRpY3Mub3JnL0NFX0NBQ1R1cyhDb21wdXRlckFpZGVkQ01FVHJhY2tpbmcpXzIwMjUwMzI3XzIyMzEwMF84NjQwLjEy" - ], - "open": 1 - } - ], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": false - }, - "tree_CCMC": { - "id": "CCMC", - "layers": [], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": true - }, - "tree_RHESSI": { - "id": "RHESSI", - "layers": [], - "visible": true, - "labels_visible": true, - "markers_visible": true, - "layer_available_visible": true - } - }, "scale": true, "scaleType": "earth", "scaleX": -2334,