Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
23 commits
Select commit Hold shift + click to select a range
4f50311
Bump urllib3 from 2.6.0 to 2.6.3
dependabot[bot] Jan 8, 2026
986f60b
remove non functional comment: snyk:ignore
wingechr Jan 8, 2026
cca1575
#2007 fix insecure redirect
wingechr Jan 8, 2026
a2deb8d
[pre-commit.ci] auto fixes from pre-commit.com hooks
pre-commit-ci[bot] Jan 8, 2026
bed7427
Merge pull request #2210 from OpenEnergyPlatform/nfdi-security-issues-b
wingechr Jan 8, 2026
b49170c
Merge pull request #2209 from OpenEnergyPlatform/dependabot/pip/urlli…
wingechr Jan 8, 2026
96474a4
add wizard.js andmetaedit.js to vite assets
wingechr Jan 8, 2026
a704599
fix tooltip
wingechr Jan 8, 2026
a8bff0c
formatting
wingechr Jan 13, 2026
4a91cd8
#2219: update bundle permission decorator to handle multiple bundle o…
jh-RLI Feb 3, 2026
348a11e
2219: fix the delete button visibility for users who do not have perm…
jh-RLI Feb 3, 2026
8a2edae
2219: fix the delete button visibility for users who do not have perm…
jh-RLI Feb 3, 2026
b2a5dde
#2219: update changelog
jh-RLI Feb 3, 2026
1a88838
#2219: Fix the pagination widget placement when browsing bundles
jh-RLI Feb 3, 2026
d20cd81
2219:
jh-RLI Feb 3, 2026
849e5b3
2219: Fix import
jh-RLI Feb 3, 2026
01a7891
2219: Update changelog
jh-RLI Feb 3, 2026
1f38ea2
Add helper management command to fix user access permissions to table…
jh-RLI Feb 4, 2026
ee42dc6
Merge pull request #2220 from OpenEnergyPlatform/bugfix-2219-fix-bund…
jh-RLI Feb 5, 2026
6fc0397
Fix missing SPDX ref
jh-RLI Feb 6, 2026
78811f7
Merge branch 'develop' of https://github.com/OpenEnergyPlatform/oepla…
jh-RLI Feb 6, 2026
efa5134
Bump changelog
jh-RLI Feb 6, 2026
f69456f
bump version -> v1.6.3
jh-RLI Feb 6, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .bumpversion.cfg
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
[bumpversion]
current_version = 1.6.2
current_version = 1.6.3

[bumpversion:file:VERSION]

Expand Down
6 changes: 3 additions & 3 deletions CITATION.cff
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
cff-version: 1.6.2
cff-version: 1.6.3
message: "If you use this software, please cite it using these metadata."
authors:
- family-names: "Hülk"
Expand Down Expand Up @@ -28,7 +28,7 @@ authors:
title: "Open Energy Family - Open Energy Platform (OEP)"
type: software
license: AGPL-3.0-or-later
version: 1.6.2
version: 1.6.3
doi:
date-released: 2026-01-07
date-released: 2026-02-06
url: "https://github.com/OpenEnergyPlatform/oeplatform/"
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
1.6.2
1.6.3
2 changes: 1 addition & 1 deletion base/management/commands/check_links.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ def iter_links(url, parent_url=None, root_url=None, no_external=False):
res = requests.get(
url,
stream=True, # stream because sometimes we dont actually load all the content
verify=False, # snyk:ignore this is ok here, because we just run it in development to test if urls still exist # noqa
verify=False, # this is ok here, because we just run it in development to test if urls still exist # noqa
headers={"User-Agent": "Mozilla/5.0"},
)
cache[url] = res.status_code
Expand Down
125 changes: 125 additions & 0 deletions dataedit/management/commands/assign_users_admin_table_permission.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
"""
SPDX-FileCopyrightText: 2025 Jonas Huber <https://github.com/jh-RLI> © Reiner Lemoine Institut
SPDX-License-Identifier: AGPL-3.0-or-later
""" # noqa: 501

from __future__ import annotations

from pathlib import Path

from django.core.management.base import BaseCommand, CommandError
from django.db import transaction

from dataedit.models import Table
from login.models import myuser
from login.utils import assign_table_holder


class Command(BaseCommand):
help = "Patch table owners by assigning a user as permission"
"holder (via assign_table_holder)."

def add_arguments(self, parser):
user_group = parser.add_mutually_exclusive_group(required=True)
user_group.add_argument("--user-id", type=int, help="User id (myuser.pk)")
user_group.add_argument("--username", type=str, help="Username (myuser.name)")
user_group.add_argument("--email", type=str, help="Email (myuser.email)")

parser.add_argument(
"--from-file",
type=str,
default=None,
help="Read table names from file (one per line; blank lines"
"and #comments ignored).",
)
parser.add_argument(
"table_names",
nargs="*",
help="Table names (edut_00) or schema-qualified (data.edut_00).",
)
parser.add_argument(
"--dry-run",
action="store_true",
help="Don't write changes; only show what would happen.",
)

def _resolve_user(self, options) -> myuser:
if options["user_id"] is not None:
return myuser.objects.get(pk=options["user_id"])
if options["username"]:
return myuser.objects.get(name=options["username"])
if options["email"]:
return myuser.objects.get(email=options["email"])
raise CommandError("No user selector provided (should be unreachable).")

def _load_names(self, options) -> list[str]:
names = list(options["table_names"] or [])

if options["from_file"]:
p = Path(options["from_file"])
if not p.exists():
raise CommandError(f"--from-file path does not exist: {p}")
for line in p.read_text(encoding="utf-8").splitlines():
line = line.strip()
if not line or line.startswith("#"):
continue
names.append(line)

if not names:
raise CommandError(
"No table names provided. Use positional names or --from-file."
)
return names

@staticmethod
def _normalize_table_name(raw: str) -> str:
raw = raw.strip()
# Accept `data.<name>` (schema is always data in your setup)
if raw.startswith("data."):
return raw.split(".", 1)[1]
return raw

def handle(self, *args, **options):
try:
user = self._resolve_user(options)
except myuser.DoesNotExist as e:
raise CommandError(f"User not found: {e}") from e

dry_run = options["dry_run"]
raw_names = self._load_names(options)
table_names = [self._normalize_table_name(n) for n in raw_names]

missing = []
changed = 0

with transaction.atomic():
for name in table_names:
table = Table.objects.filter(name=name).first()
if not table:
missing.append(name)
self.stdout.write(self.style.ERROR(f"missing: {name}"))
continue

if dry_run:
self.stdout.write(
self.style.WARNING(
f"[DRY] would assign holder {user} to {name}"
)
)
continue

# This should create/update the proper UserPermission row(s)
# exactly like normal table creation does.
assign_table_holder(user=user, table=table)

changed += 1
self.stdout.write(self.style.SUCCESS(f"assigned: {user} -> {name}"))

if dry_run:
transaction.set_rollback(True)

self.stdout.write(
self.style.SUCCESS(
f"Done. assigned={changed}, missing={len(missing)}, dry_run={dry_run}"
)
)
3 changes: 3 additions & 0 deletions dataedit/static/wizard/wizard.js
Original file line number Diff line number Diff line change
Expand Up @@ -972,3 +972,6 @@ window.Wizard = function (config) {
$("#wizard-loading").hide();
})();
};

/* notify inline code that Wizard is loaded */
window.dispatchEvent(new Event("Wizard:ready"));
6 changes: 3 additions & 3 deletions dataedit/templates/dataedit/meta_edit.html
Original file line number Diff line number Diff line change
Expand Up @@ -128,15 +128,15 @@ <h5 class="modal-title" id="modalLabel">
{% compress js %}
<script src="{% static 'metaedit/vendor/json-editor-2.9.1/jsoneditor.min.js' %}"></script>
<script src="{% static 'modelview/htmx.min.js' %}"></script>
<script src="{% static 'metaedit/metaedit.js' %}"></script>
{% endcompress %}
{% vite_asset "dataedit/static/metaedit/metaedit.js" %}
<!-- fix imports below - we dont use cdn anymore -->
<script src="{{ EXTERNAL_URLS.unpkg__trevoreyre_autocomplete_js }}"></script>
<link rel="stylesheet"
href="{{ EXTERNAL_URLS.unpkg__trevoreyre_autocomplete_js_dist_style_css }}" />
<script>
/* only execute after MetaEdit is fully loaded */
// window.addEventListener("MetaEdit:ready", () => { /* TODO MetaEdit:ready */
window.addEventListener("MetaEdit:ready", () => {

var createUrl = '{% url "oeo_ext:oeo-ext-plugin-ui-create" %}';
var config = JSON.parse("{{ config|escapejs }}");
Expand Down Expand Up @@ -179,6 +179,6 @@ <h5 class="modal-title" id="modalLabel">
// Set up tab filtering
hideTabsFilter(["Meta Metadata", "Embargo Period", "Dialect", "Review"]);

// }); /* TODO MetaEdit:ready */
});
</script>
{% endblock after-body-bottom-js %}
21 changes: 12 additions & 9 deletions dataedit/templates/dataedit/wizard.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@
{% load django_bootstrap5 %}
{% load compress %}
{% block after-head %}
<link href="{% static 'wizard/wizard.css' %}" rel="stylesheet" />
{% compress css %}
<link href="{% static 'wizard/wizard.css' %}" rel="stylesheet" />
{% endcompress %}
{% endblock after-head %}
{% block site-header %}
<div class="main-header">
Expand Down Expand Up @@ -379,15 +381,16 @@ <h4>Preview and upload</h4>
</div>
</div>
<script src="{% static 'wizard/vendor/papaparse-5.0.2/papaparse.min.js' %}"></script>
{% compress js %}
<script src="{% static 'wizard/wizard.js' %}"></script>
{% endcompress %}
{% vite_asset "dataedit/static/wizard/wizard.js" %}
<script>
$(document).ready(function () {
var config = JSON.parse("{{ config|escapejs }}");
var wizard = Wizard(config);

$('[data-bs-toggle="tooltip"]').tooltip();
/* only execute after Wizard is fully loaded */
window.addEventListener("Wizard:ready", () => {
// also ensure jquery has been loaded
$(document).ready(function () {
var config = JSON.parse("{{ config|escapejs }}");
var wizard = Wizard(config);
$('[data-bs-toggle="tooltip"]').tooltip();
});
});
</script>
{% endblock after-body-bottom-js %}
2 changes: 1 addition & 1 deletion dataedit/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,7 @@ def tag_table_add_view(request: HttpRequest) -> HttpResponse:
# generic error message
messages.error(request, "Something went wrong")

redirect_url = request.META.get("HTTP_REFERER") or reverse("dataedit:topic-list")
redirect_url = reverse("dataedit:view", kwargs={"table": table_obj.name})
return redirect(redirect_url)


Expand Down
3 changes: 2 additions & 1 deletion factsheet/frontend/src/components/customAutocomplete.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ import {
DialogActions,
Button
} from '@mui/material';
import { styled } from '@mui/material/styles';
import styled from '@mui/material/styles/styled';

import { createFilterOptions } from '@mui/material/Autocomplete';
import CheckBoxOutlineBlankIcon from '@mui/icons-material/CheckBoxOutlineBlank';
import CheckBoxIcon from '@mui/icons-material/CheckBox';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@ import {
Chip,
Typography
} from '@mui/material';
import { styled } from '@mui/material/styles';
import styled from '@mui/material/styles/styled';

import { createFilterOptions } from '@mui/material/Autocomplete';
import CheckBoxOutlineBlankIcon from '@mui/icons-material/CheckBoxOutlineBlank';
import CheckBoxIcon from '@mui/icons-material/CheckBox';
Expand Down
39 changes: 5 additions & 34 deletions factsheet/frontend/src/components/customSwapButton.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,61 +7,32 @@
//
// SPDX-License-Identifier: AGPL-3.0-or-later

import React, { useState, useEffect } from 'react';
import React, { useState } from 'react';
import Button from '@mui/material/Button';
import ButtonGroup from '@mui/material/ButtonGroup';
import ArrowBackIcon from '@mui/icons-material/ArrowBack';
import RemoveRedEyeOutlinedIcon from '@mui/icons-material/RemoveRedEyeOutlined';
import EditOutlinedIcon from '@mui/icons-material/EditOutlined';
import Tooltip from '@mui/material/Tooltip';
import { Link } from 'react-router-dom';
import axios from 'axios';


import Snackbar from '@mui/material/Snackbar';
import Alert from '@mui/material/Alert';
import AlertTitle from '@mui/material/AlertTitle';
import CSRFToken from './csrfToken';

import conf from "../conf.json";

const ColorToggleButton = (props) => {
const [isOwner, setIsOwner] = useState(false);
const ColorToggleButton = ({ handleSwap, isOwner, isOwnerLoading }) => {
const [snackbarOpen, setNotTheOwner] = useState(false);

const param_2 = String(window.location.href).split('/')[5];

useEffect(() => {
// Replace 'bundle_id' with the actual ID of the ScenarioBundle you want to check
const bundleId = param_2; // Assuming you pass the uid as a prop
// Make the API call to check if the user is the owner
axios.post(conf.toep + `scenario-bundles/check-owner/${bundleId}/`,
{
uid: bundleId
},
{
headers: { 'X-CSRFToken': CSRFToken() }
})
.then(response => {
// Assuming the response.data contains the ownership information
setIsOwner(response.data.isOwner);
})
.catch(error => {
console.error('Error checking ownership:', error);
// Handle errors if needed
});
}, [param_2]); // Dependency array includes props.uid to re-run the effect when it changes

const handleChange = (event, mode) => {
// Only allow the 'edit' action if the user is the owner
if (mode === 'edit' && !isOwner) {
if (mode === "edit" && (isOwnerLoading || !isOwner)) {
setNotTheOwner(true);
return;
}

props.handleSwap(mode);
handleSwap(mode);
};


const handleNotTheOwnerClose = (event, reason) => {
if (reason === 'clickaway') {
return;
Expand Down
Loading