Skip to content
Draft
1 change: 1 addition & 0 deletions src/_main_/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@
'api.middlewares.translation_middleware.TranslationMiddleware',
'authentication.middleware.MassenergizeJWTAuthMiddleware',
'django_hosts.middleware.HostsResponseMiddleware',
"api.middlewares.gate_middleware.GateMiddleware",
'_main_.utils.metrics.middleware.MetricsMiddleware'
]

Expand Down
3 changes: 3 additions & 0 deletions src/_main_/utils/massenergize_logger/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,9 @@

if not EnvConfig.can_send_logs_to_cloudwatch():
return

if not message:
return

Check warning on line 21 in src/_main_/utils/massenergize_logger/__init__.py

View check run for this annotation

Codecov / codecov/patch

src/_main_/utils/massenergize_logger/__init__.py#L20-L21

Added lines #L20 - L21 were not covered by tests

if exception:
extra['exception'] = exception
Expand Down
20 changes: 13 additions & 7 deletions src/api/decorators.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@
"""
from django.core.exceptions import PermissionDenied
from django.http import HttpResponse
from _main_.utils.constants import DEFAULT_SOURCE_LANGUAGE_CODE
from _main_.utils.context import Context
from functools import wraps
from _main_.utils.massenergize_errors import CustomMassenergizeError, NotAuthorizedError
from _main_.utils.massenergize_errors import NotAuthorizedError
from _main_.utils.massenergize_logger import log
from django.core.cache import cache

from _main_.utils.utils import is_test_mode

def x_frame_options_exempt(view_func):
@wraps(view_func)
def wrapped_view(*args, **kwargs):
Expand Down Expand Up @@ -94,22 +97,25 @@
context: Context = request.context
args = context.args

subdomain = args.get('subdomain', args.get("id", "None"))
locale = context.preferred_language or 'en'
# subdomain = args.get('subdomain', args.get("id", "None"))
key = ".".join([v for v in args.values()])

locale = context.preferred_language or DEFAULT_SOURCE_LANGUAGE_CODE

force_refresh = context.args.get('force_refresh', False)

cache_key = f"{func.__module__}.{func.__name__}.{key}.{locale}"

if force_refresh:
cache.delete(f"{func.__module__}.{func.__name__}.{subdomain}.{locale}")
cache.delete(cache_key)

Check warning on line 110 in src/api/decorators.py

View check run for this annotation

Codecov / codecov/patch

src/api/decorators.py#L110

Added line #L110 was not covered by tests

cache_key = f"{func.__module__}.{func.__name__}.{subdomain}.{locale}"
cached_data = cache.get(cache_key)

if cached_data and not force_refresh:
if cached_data and not force_refresh and not is_test_mode():
return cached_data
else:
result = func(handler,request,**kwargs)
cache.set(cache_key, result)
cache.set(cache_key, result, timeout=3600)
return result

wrapper.__doc__ = func.__doc__
Expand Down
2 changes: 1 addition & 1 deletion src/api/handlers/action.py
Original file line number Diff line number Diff line change
Expand Up @@ -111,7 +111,7 @@ def submit(self, request):
return err
return MassenergizeResponse(data=action_info)

# @cached_request
@cached_request
def list(self, request):
context: Context = request.context
args: dict = context.args
Expand Down
5 changes: 3 additions & 2 deletions src/api/handlers/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
from _main_.utils.massenergize_response import MassenergizeResponse
from types import FunctionType as function
from _main_.utils.context import Context
from api.decorators import admins_only, super_admins_only, login_required
from api.decorators import admins_only, cached_request, super_admins_only, login_required
from api.store.common import expect_media_fields


Expand Down Expand Up @@ -238,7 +238,8 @@ def list_exceptions(self, request):
return err

return MassenergizeResponse(data=exceptions)


@cached_request
def list(self, request):

context: Context = request.context
Expand Down
2 changes: 1 addition & 1 deletion src/api/handlers/team.py
Original file line number Diff line number Diff line change
Expand Up @@ -88,7 +88,7 @@ def list(self, request):

return MassenergizeResponse(data=team_info)

# @cached_request
@cached_request
def team_stats(self, request):
context: Context = request.context
args: dict = context.args
Expand Down
2 changes: 1 addition & 1 deletion src/api/handlers/testimonial.py
Original file line number Diff line number Diff line change
Expand Up @@ -143,7 +143,7 @@ def submit(self, request):
return err
return MassenergizeResponse(data=testimonial_info)

# @cached_request
@cached_request
def list(self, request):
context = request.context
args = context.args
Expand Down
2 changes: 1 addition & 1 deletion src/api/handlers/vendor.py
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,7 @@ def submit(self, request):
return err
return MassenergizeResponse(data=vendor_info)

# @cached_request
@cached_request
def list(self, request):
context: Context = request.context
args = context.get_request_body()
Expand Down
18 changes: 18 additions & 0 deletions src/api/middlewares/gate_middleware.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
from django.http import HttpResponse
from django.urls import resolve, Resolver404

class GateMiddleware:
def __init__(self, get_response):
self.get_response = get_response

def __call__(self, request):
try:
resolve(request.path)
except Resolver404:
return HttpResponse("This endpoint does not exist.", status=404)

Check warning on line 12 in src/api/middlewares/gate_middleware.py

View check run for this annotation

Codecov / codecov/patch

src/api/middlewares/gate_middleware.py#L11-L12

Added lines #L11 - L12 were not covered by tests

response = self.get_response(request)
return response



1 change: 0 additions & 1 deletion src/api/services/team.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@
from _main_.utils.pagination import paginate
from api.store.team import TeamStore
from api.store.message import MessageStore
from api.utils.api_utils import get_sender_email
from api.utils.filter_functions import sort_items
from database.models import TeamMember
from _main_.utils.context import Context
Expand Down
106 changes: 79 additions & 27 deletions src/api/store/team.py
Original file line number Diff line number Diff line change
Expand Up @@ -85,43 +85,95 @@ def list_teams(self, context: Context, args) -> Tuple[list, MassEnergizeAPIError
except Exception as e:
log.exception(e)
return None, CustomMassenergizeError(e)


# def team_stats_v2(self, context: Context, args) -> Tuple[list, MassEnergizeAPIError]:
# try:
# community = get_community_or_die(context, args)
# teams = Team.objects.filter(communities__id=community.id, is_deleted=False)

def team_stats(self, context: Context, args) -> Tuple[list, MassEnergizeAPIError]:
try:
community = get_community_or_die(context, args)
teams = Team.objects.filter(communities__id=community.id, is_deleted=False)

# show unpublished teams only in sandbox.
# TODO: Better solution would be to show also for the user who created the team, but more complicated
if not context.is_sandbox:
teams = teams.filter(is_published=True)
# # show unpublished teams only in sandbox.
# # TODO: Better solution would be to show also for the user who created the team, but more complicated
# if not context.is_sandbox:
# teams = teams.filter(is_published=True)

ans = []
for team in teams:
res = {"members": 0, "households": 0, "actions": 0, "actions_completed": 0, "actions_todo": 0, "carbon_footprint_reduction": 0}
res["team"] = team.simple_json()
# ans = []
# for team in teams:
# res = {"members": 0, "households": 0, "actions": 0, "actions_completed": 0, "actions_todo": 0, "carbon_footprint_reduction": 0}
# res["team"] = team.simple_json()

users = get_team_users(team)
res["members"] = 0
# users = get_team_users(team)
# res["members"] = 0

# for user in users:
# # only include users that have joined the platform
# if user.accepts_terms_and_conditions:
# res["members"] += 1
# res["households"] += user.real_estate_units.count()
# actions = user.useractionrel_set.all()
# res["actions"] += len(actions)
# done_actions = actions.filter(status="DONE").prefetch_related('action__calculator_action')
# res["actions_completed"] += done_actions.count()
# res["actions_todo"] += actions.filter(status="TODO").count()
# for done_action in done_actions:
# if done_action.action and done_action.action.calculator_action:
# res["carbon_footprint_reduction"] += AverageImpact(done_action.action.calculator_action, done_action.date_completed)

# ans.append(res)

# return ans, None
# except Exception as e:
# log.exception(e)
# return None, CustomMassenergizeError(e)

for user in users:
# only include users that have joined the platform
if user.accepts_terms_and_conditions:

def team_stats(self, context: Context, args) -> Tuple[list, MassEnergizeAPIError]:
try:
community = get_community_or_die(context, args)

teams = Team.objects.filter(communities__id=community.id, is_deleted=False)
if not context.is_sandbox:
teams = teams.filter(is_published=True)

team_members = TeamMember.objects.filter(
Q(team__in=teams) | Q(team__parent__in=teams, team__is_published=True, team__is_deleted=False),
is_deleted=False
).select_related('team', 'user').prefetch_related(
'user__real_estate_units',
'user__useractionrel_set__action__calculator_action'
)

data = []
teams_dict = {}

for member in team_members:
team = member.team
if team.id not in teams_dict:
teams_dict[team.id] = {
"team": team.simple_json(),
"members": 0,
"households": 0,
"actions": 0,
"actions_completed": 0,
"actions_todo": 0,
"carbon_footprint_reduction": 0
}

res = teams_dict[team.id]
res["members"] += 1
user = member.user
res["households"] += user.real_estate_units.count()
actions = user.useractionrel_set.all()
res["actions"] += len(actions)
done_actions = actions.filter(status="DONE").prefetch_related('action__calculator_action')
res["actions_completed"] += done_actions.count()
res["actions_todo"] += actions.filter(status="TODO").count()
res["actions"] += actions.count()
done_actions = [action for action in actions if action.status == "DONE"]
res["actions_completed"] += len(done_actions)
res["actions_todo"] += len([action for action in actions if action.status == "TODO"])
for done_action in done_actions:
if done_action.action and done_action.action.calculator_action:
res["carbon_footprint_reduction"] += AverageImpact(done_action.action.calculator_action, done_action.date_completed)

ans.append(res)
if done_action.action and done_action.action.calculator_action:
res["carbon_footprint_reduction"] += AverageImpact(done_action.action.calculator_action, done_action.date_completed)

return ans, None
data = list(teams_dict.values())
return data, None
except Exception as e:
log.exception(e)
return None, CustomMassenergizeError(e)
Expand Down
3 changes: 0 additions & 3 deletions src/api/tests/integration/test_communities.py
Original file line number Diff line number Diff line change
Expand Up @@ -420,9 +420,6 @@ def test_update_community_notification_settings(self):
# test update community notification settings not logged in
Console.header("Integration: update_community_notification_settings")
args = {"id": self.community_notification_setting.id, "is_active": True}
signinAs(self.client, None)
update_response = self.client.post('/api/communities.notifications.settings.update', urlencode(args), content_type="application/x-www-form-urlencoded").toDict()
self.assertFalse(update_response["success"])

# test update community notification settings logged as user
signinAs(self.client, self.USER)
Expand Down
2 changes: 1 addition & 1 deletion src/database/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -2068,7 +2068,7 @@ def info(self):
"community":{
"id": self.community.id,
"name": self.community.name,
},
} if self.community else None,
"image": get_json_if_not_none(self.image),
}

Expand Down
4 changes: 2 additions & 2 deletions src/website/views.py
Original file line number Diff line number Diff line change
Expand Up @@ -310,8 +310,8 @@

def _get_file_url(image):
if not image:
return None
return image.file.url if image.file else None
return ""
return image.file.url if image.file else ""

Check warning on line 314 in src/website/views.py

View check run for this annotation

Codecov / codecov/patch

src/website/views.py#L313-L314

Added lines #L313 - L314 were not covered by tests


def _separate_communities(communities, lat, long):
Expand Down
Loading