Skip to content

Commit 5b619da

Browse files
authored
Merge branch 'develop' into Fix-compliance-filter-groups
2 parents c536422 + 3899852 commit 5b619da

39 files changed

+491
-160
lines changed

CHANGELOG.md

+38
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,41 @@
1+
# SEED Version 3.2.4
2+
3+
<!-- Release notes generated using configuration in .github/release.yml at 3.2.4-release-prep -->
4+
5+
## What's Changed
6+
### New Features 🎉
7+
* Django settings endpoint by @kflemin in https://github.com/SEED-platform/seed/pull/4936
8+
### Improvements 📈
9+
* Move JWT token claims to v3_users_current by @crutan in https://github.com/SEED-platform/seed/pull/4939
10+
* Add user serializer by @crutan in https://github.com/SEED-platform/seed/pull/4940
11+
### Bug Fixes 🐛
12+
* Make data type column wide enough to see completely by @crutan in https://github.com/SEED-platform/seed/pull/4919
13+
* Fix group meter interval by @haneslinger in https://github.com/SEED-platform/seed/pull/4937
14+
15+
16+
**Full Changelog**: https://github.com/SEED-platform/seed/compare/v3.2.3...v3.2.4
17+
18+
# SEED Version 3.2.3
19+
20+
<!-- Release notes generated using configuration in .github/release.yml at 3.2.3-release-prep -->
21+
22+
## What's Changed
23+
### Improvements 📈
24+
* Add meter of type Electric to BSyncR analysis by @kflemin in https://github.com/SEED-platform/seed/pull/4923
25+
* Save org settings & 2fa prompt by @perryr16 in https://github.com/SEED-platform/seed/pull/4905
26+
* Add Simple JWT to authorization setup by @crutan in https://github.com/SEED-platform/seed/pull/4926
27+
* Portfolio Summary updates by @perryr16 in https://github.com/SEED-platform/seed/pull/4909
28+
### Maintenance 🧹
29+
* Remove inventory list `Data` nav item by @axelstudios in https://github.com/SEED-platform/seed/pull/4920
30+
* Remove server settings from the session cookie by @axelstudios in https://github.com/SEED-platform/seed/pull/4927
31+
### Bug Fixes 🐛
32+
* Fix upgrade recommendation by @haneslinger in https://github.com/SEED-platform/seed/pull/4917
33+
* Fix inventory groups add inventory bug by @perryr16 in https://github.com/SEED-platform/seed/pull/4932
34+
* Show default display name on analyses by @perryr16 in https://github.com/SEED-platform/seed/pull/4924
35+
36+
37+
**Full Changelog**: https://github.com/SEED-platform/seed/compare/v3.2.2...v3.2.3
38+
139
# SEED Version 3.2.2
240

341
<!-- Release notes generated using configuration in .github/release.yml at 3.2.2-release-prep -->

config/settings/common.py

+10
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
"""
55

66
import os
7+
from datetime import timedelta
78
from distutils.util import strtobool
89

910
from django.utils.translation import gettext_lazy as _
@@ -101,6 +102,7 @@
101102
"two_factor.plugins.phonenumber", # <- if you want phone number capability.
102103
"two_factor.plugins.email", # <- if you want email capability.
103104
# "two_factor.plugins.yubikey", # <- for yubikey capability.
105+
"rest_framework_simplejwt",
104106
)
105107

106108

@@ -268,6 +270,7 @@
268270
# Django Rest Framework
269271
REST_FRAMEWORK = {
270272
"DEFAULT_AUTHENTICATION_CLASSES": (
273+
"rest_framework_simplejwt.authentication.JWTAuthentication",
271274
"rest_framework.authentication.SessionAuthentication",
272275
"seed.authentication.SEEDAuthentication",
273276
),
@@ -304,6 +307,13 @@
304307
"LOGOUT_URL": "/accounts/logout",
305308
}
306309

310+
SIMPLE_JWT = {
311+
"ACCESS_TOKEN_LIFETIME": timedelta(minutes=5),
312+
"AUTH_HEADER_TYPES": ("Bearer",),
313+
"TOKEN_OBTAIN_SERIALIZER": "seed.landing.serializers.SeedTokenObtainPairSerializer",
314+
"ROTATE_REFRESH_TOKENS": True,
315+
}
316+
307317
try:
308318
EEEJ_LOAD_SMALL_TEST_DATASET = bool(strtobool(os.environ.get("EEEJ_LOAD_SMALL_TEST_DATASET", "False")))
309319
except Exception:

config/urls.py

+7-2
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,13 @@
1010
from drf_yasg import openapi
1111
from drf_yasg.views import get_schema_view
1212
from rest_framework import permissions
13+
from rest_framework_simplejwt.views import TokenObtainPairView, TokenRefreshView
1314
from two_factor.urls import urlpatterns as tf_urls
1415

1516
from config.views import robots_txt
1617
from seed.api.base.urls import urlpatterns as api
1718
from seed.landing.views import CustomLoginView, password_reset_complete, password_reset_confirm, password_reset_done
18-
from seed.views.main import angular_js_tests, health_check, version
19+
from seed.views.main import angular_js_tests, config, health_check, version
1920

2021
schema_view = get_schema_view(
2122
openapi.Info(
@@ -51,9 +52,13 @@ def trigger_error(request):
5152
# root configuration items
5253
re_path(r"^i18n/", include("django.conf.urls.i18n")),
5354
re_path(r"^robots\.txt", robots_txt, name="robots_txt"),
54-
# API
55+
# API (explicit no-auth)
56+
re_path(r"^api/config/$", config, name="config"),
5557
re_path(r"^api/health_check/$", health_check, name="health_check"),
58+
# API
5659
re_path(r"^api/swagger/$", schema_view.with_ui("swagger", cache_timeout=0), name="schema-swagger-ui"),
60+
re_path(r"^api/token/$", TokenObtainPairView.as_view(), name="token_obtain_pair"),
61+
re_path(r"^api/token/refresh/$", TokenRefreshView.as_view(), name="token_refresh"),
5762
re_path(r"^api/version/$", version, name="version"),
5863
re_path(r"^api/", include((api, "seed"), namespace="api")),
5964
re_path(r"^account/login", CustomLoginView.as_view(), name="login"),

docs/source/migrations.rst

+8
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,14 @@ local_untracked.py file
3838
),
3939
)
4040
41+
Version 3.2.4
42+
-------------
43+
- There are no special migrations needed for this version. Simply run ``./manage.py migrate``.
44+
45+
Version 3.2.3
46+
-------------
47+
- There are no special migrations needed for this version. Simply run ``./manage.py migrate``.
48+
4149
Version 3.2.2
4250
-------------
4351
- There are no special migrations needed for this version. Simply run ``./manage.py migrate``.

locale/en_US/LC_MESSAGES/django.mo

394 Bytes
Binary file not shown.

locale/en_US/LC_MESSAGES/django.po

+18
Original file line numberDiff line numberDiff line change
@@ -360,6 +360,12 @@ msgstr "Advanced Settings"
360360
msgid "Alias"
361361
msgstr "Alias"
362362

363+
msgid "All Canonical Fields"
364+
msgstr "All Canonical Fields"
365+
366+
msgid "All Extra Data Fields"
367+
msgstr "All Extra Data Fields"
368+
363369
msgid "An Audit Template organization token, user email and password are required"
364370
msgstr "An Audit Template organization token, user email and password are required"
365371

@@ -970,6 +976,12 @@ msgstr "Create a New Sub-Organization"
970976
msgid "Create a Program to get started!"
971977
msgstr "Create a Program to get started!"
972978

979+
msgid "Create a Property"
980+
msgstr "Create a Property"
981+
982+
msgid "Create a Tax Lot"
983+
msgstr "Create a Tax Lot"
984+
973985
msgid "Create a new rule"
974986
msgstr "Create a new rule"
975987

@@ -4342,6 +4354,9 @@ msgstr "Unsuccessful Exports"
43424354
msgid "Until last date of"
43434355
msgstr "Until last date of"
43444356

4357+
msgid "Update"
4358+
msgstr "Update"
4359+
43454360
msgid "Update Charts"
43464361
msgstr "Update Charts"
43474362

@@ -4351,6 +4366,9 @@ msgstr "Update Derived Data"
43514366
msgid "Update Filters"
43524367
msgstr "Update Filters"
43534368

4369+
msgid "Update Password"
4370+
msgstr "Update Password"
4371+
43544372
msgid "Update Property Labels"
43554373
msgstr "Update Property Labels"
43564374

locale/es/LC_MESSAGES/django.mo

352 Bytes
Binary file not shown.

locale/es/LC_MESSAGES/django.po

+19-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ msgstr ""
55
"Content-Transfer-Encoding: 8bit\n"
66
"X-Generator: lokalise.com\n"
77
"Project-Id-Version: SEED Platform\n"
8-
"PO-Revision-Date: 2024-12-14 00:26\n"
8+
"PO-Revision-Date: 2025-02-03 16:29\n"
99
"Last-Translator: lokalise.com\n"
1010
"Language-Team: lokalise.com\n\n"
1111
"Language: es\n"
@@ -461,6 +461,12 @@ msgstr "Configuración avanzada"
461461
msgid "Alias"
462462
msgstr "Alias"
463463

464+
msgid "All Canonical Fields"
465+
msgstr "Todos los campos canónicos"
466+
467+
msgid "All Extra Data Fields"
468+
msgstr "Todos los campos de datos adicionales"
469+
464470
#, fuzzy
465471
msgid "An Audit Template organization token, user email and password are required"
466472
msgstr "Se requiere un token de organización de Plantilla de Auditoría, un correo electrónico de usuario y una contraseña"
@@ -1245,6 +1251,12 @@ msgstr "Crear una nueva suborganización"
12451251
msgid "Create a Program to get started!"
12461252
msgstr "Cree un programa para empezar"
12471253

1254+
msgid "Create a Property"
1255+
msgstr "Crear una propiedad"
1256+
1257+
msgid "Create a Tax Lot"
1258+
msgstr "Crear un lote de impuestos"
1259+
12481260
#, fuzzy
12491261
msgid "Create a new rule"
12501262
msgstr "Crear una nueva regla"
@@ -5632,6 +5644,9 @@ msgstr "Exportaciones fallidas"
56325644
msgid "Until last date of"
56335645
msgstr "Hasta la última fecha de"
56345646

5647+
msgid "Update"
5648+
msgstr "Actualizar"
5649+
56355650
#, fuzzy
56365651
msgid "Update Charts"
56375652
msgstr "Actualizar gráficos"
@@ -5644,6 +5659,9 @@ msgstr "Actualizar datos derivados"
56445659
msgid "Update Filters"
56455660
msgstr "Actualizar filtros"
56465661

5662+
msgid "Update Password"
5663+
msgstr "Actualizar contraseña"
5664+
56475665
#, fuzzy
56485666
msgid "Update Property Labels"
56495667
msgstr "Actualizar etiquetas de propiedad"

locale/fr_CA/LC_MESSAGES/django.mo

389 Bytes
Binary file not shown.

locale/fr_CA/LC_MESSAGES/django.po

+18
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,12 @@ msgstr "Réglages avancés"
364364
msgid "Alias"
365365
msgstr "Alias"
366366

367+
msgid "All Canonical Fields"
368+
msgstr "Tous les champs canoniques"
369+
370+
msgid "All Extra Data Fields"
371+
msgstr "Tous les champs de données supplémentaires"
372+
367373
msgid "An Audit Template organization token, user email and password are required"
368374
msgstr "Un jeton d'organisation Audit Template, un e-mail d'utilisateur et un mot de passe sont requis"
369375

@@ -980,6 +986,12 @@ msgstr "Créer une nouvelle sous-organisation"
980986
msgid "Create a Program to get started!"
981987
msgstr "Créez un programme pour commencer !"
982988

989+
msgid "Create a Property"
990+
msgstr "Créer une propriété"
991+
992+
msgid "Create a Tax Lot"
993+
msgstr "Créer un lot fiscal"
994+
983995
msgid "Create a new rule"
984996
msgstr "Créer une nouvelle règle"
985997

@@ -4376,6 +4388,9 @@ msgstr "Exportations infructueuses"
43764388
msgid "Until last date of"
43774389
msgstr "Jusqu'à la dernière date de"
43784390

4391+
msgid "Update"
4392+
msgstr "Mise à jour"
4393+
43794394
msgid "Update Charts"
43804395
msgstr "Mettre à jour les graphiques"
43814396

@@ -4385,6 +4400,9 @@ msgstr "Mettre à jour les données dérivées"
43854400
msgid "Update Filters"
43864401
msgstr "Mise à jour les filtres"
43874402

4403+
msgid "Update Password"
4404+
msgstr "Mettre à jour le mot de passe"
4405+
43884406
msgid "Update Property Labels"
43894407
msgstr "Mettre à jour les étiquettes de propriété"
43904408

package-lock.json

+2-2
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "seed",
3-
"version": "3.2.2",
3+
"version": "3.2.4",
44
"description": "Standard Energy Efficiency Data (SEED) Platform™",
55
"license": "SEE LICENSE IN LICENSE.md",
66
"directories": {

requirements/base.txt

+1
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ django-pint==0.7.3
2727

2828
# API
2929
djangorestframework==3.15.1 # Update after Django 4.2
30+
djangorestframework-simplejwt==5.3.1 # Update after Django 4.2
3031
django-post_office==3.8.0 # Update after Django 4.2
3132
drf-yasg==1.21.7
3233
django-filter==22.1 # Update after Django 4.2 and drf-spectacular

seed/landing/models.py

+28-14
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
from django.utils import timezone
1616
from django.utils.translation import gettext_lazy as _
1717
from rest_framework import exceptions
18+
from rest_framework_simplejwt.exceptions import TokenError
19+
from rest_framework_simplejwt.tokens import AccessToken
1820

1921
from seed.lib.superperms.orgs.models import Organization
2022

@@ -82,23 +84,29 @@ def process_header_request(cls, request):
8284
return None
8385

8486
try:
85-
if not auth_header.startswith("Basic"):
86-
raise exceptions.AuthenticationFailed("Only Basic HTTP_AUTHORIZATION is supported")
87-
88-
auth_header = auth_header.split()[1]
89-
auth_header = base64.urlsafe_b64decode(auth_header).decode("utf-8")
90-
username, api_key = auth_header.split(":")
91-
92-
valid_api_key = re.search("^[a-f0-9]{40}$", api_key)
93-
if not valid_api_key:
94-
raise exceptions.AuthenticationFailed("Invalid API key")
95-
96-
user = SEEDUser.objects.get(api_key=api_key, username=username)
97-
return user
87+
if auth_header.startswith("Basic"):
88+
auth_header = auth_header.split()[1]
89+
auth_header = base64.urlsafe_b64decode(auth_header).decode("utf-8")
90+
username, api_key = auth_header.split(":")
91+
92+
valid_api_key = re.search("^[a-f0-9]{40}$", api_key)
93+
if not valid_api_key:
94+
raise exceptions.AuthenticationFailed("Invalid API key")
95+
96+
user = SEEDUser.objects.get(api_key=api_key, username=username)
97+
return user
98+
elif auth_header.startswith("Bearer"):
99+
at = AccessToken(auth_header.removeprefix("Bearer "))
100+
user = SEEDUser.objects.get(pk=at["user_id"])
101+
return user
102+
else:
103+
raise exceptions.AuthenticationFailed("Only Basic HTTP_AUTHORIZATION or BEARER Tokens are supported")
98104
except ValueError:
99105
raise exceptions.AuthenticationFailed("Invalid HTTP_AUTHORIZATION Header")
106+
except TokenError:
107+
raise exceptions.AuthenticationFailed("Invalid Bearer Token")
100108
except SEEDUser.DoesNotExist:
101-
raise exceptions.AuthenticationFailed("Invalid API key")
109+
raise exceptions.AuthenticationFailed("Invalid API key or Bearer Token")
102110

103111
def get_absolute_url(self):
104112
return f"/users/{quote(self.username)}/"
@@ -149,3 +157,9 @@ def save(self, *args, **kwargs):
149157
if self.email.lower() != self.username:
150158
self.email = self.username
151159
return super().save(*args, **kwargs)
160+
161+
def serialize(self):
162+
from seed.serializers.users import UserSerializer
163+
164+
serializer = UserSerializer(self)
165+
return serializer.data

seed/landing/serializers.py

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
2+
3+
4+
class SeedTokenObtainPairSerializer(TokenObtainPairSerializer):
5+
@classmethod
6+
def get_token(cls, user):
7+
token = super().get_token(user)
8+
9+
# Add custom claims
10+
# token["name"] = f"{user.first_name} {user.last_name}".strip()
11+
12+
return token

seed/models/properties.py

+7
Original file line numberDiff line numberDiff line change
@@ -847,6 +847,13 @@ def merge_relationships(cls, merged_state, state1, state2):
847847

848848
return merged_state
849849

850+
def default_display_value(self):
851+
try:
852+
field = self.organization.property_display_field
853+
return self.extra_data.get(field) or getattr(self, field)
854+
except AttributeError:
855+
return None
856+
850857

851858
@receiver(pre_delete, sender=PropertyState)
852859
def pre_delete_state(sender, **kwargs):

0 commit comments

Comments
 (0)