Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: Add a single endpoint to fetch community page data #963

Closed
wants to merge 18 commits into from
Closed
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
0d2b72a
feat: Add site data and menu loading functionality
abdullai-t Apr 17, 2024
11cec21
feat: Remove confirm.sh and streamline environment handling
abdullai-t Apr 17, 2024
3fc0010
Refactor: :sparkles: :recycle: API utils and related components for e…
abdullai-t Apr 20, 2024
0ae1853
Refactor page settings data key in api_utils.py
abdullai-t Apr 20, 2024
49865f5
fix: Update user event eligibility checking logic
abdullai-t Apr 23, 2024
565d4d7
:recycle: refactor: Update field renaming, data fetching, and concurr…
abdullai-t Apr 24, 2024
b1e8e6f
:recycle: Ensure distinct feature flags are returned
abdullai-t Apr 24, 2024
1e04e5c
:recycle: Set IS_LOCAL to True and refactor environment path selection
abdullai-t Apr 24, 2024
0bf6a7c
:recycle: Update environment condition for LOCAL setup
abdullai-t Apr 24, 2024
75c72be
Refactor import statements and comment out unused code
abdullai-t Apr 25, 2024
c34976e
Remove obsolete site setup utilities
abdullai-t Apr 25, 2024
739bdf6
Refactor validator to expect 'endpoints' instead of 'data'
abdullai-t Apr 25, 2024
a091fee
Remove unused PAGE_SETUP_ESSENTIALS constant
abdullai-t Apr 25, 2024
176bf15
Add cookies to post request in fetch_data
abdullai-t Apr 25, 2024
adfd82f
Add donation page settings to community API
abdullai-t Apr 25, 2024
09ad315
Merge branch 'development' into mew-optimized-site-link
abdullai-t Apr 29, 2024
803d20c
Merge branch 'development' of https://github.com/massenergize/api int…
abdullai-t May 1, 2024
cfa40c3
Add TODO comment to create new endpoint in misc.py
abdullai-t May 1, 2024
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
6 changes: 6 additions & 0 deletions src/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ build-and-push-prod:
docker build -t massenergize/api .
docker tag massenergize/api:latest 202758212688.dkr.ecr.us-east-2.amazonaws.com/massenergize/api:$(VERSION)
docker push 202758212688.dkr.ecr.us-east-2.amazonaws.com/massenergize/api:$(VERSION)

eb setenv DJANGO_ENV=prod
eb deploy --label $(VERSION)

git tag prod@$(VERSION)
Expand All @@ -41,6 +43,8 @@ build-and-push-canary:
docker build -t massenergize/api-canary .
docker tag massenergize/api-canary:latest 202758212688.dkr.ecr.us-east-2.amazonaws.com/massenergize/api-canary:$(CANARY_VERSION)
docker push 202758212688.dkr.ecr.us-east-2.amazonaws.com/massenergize/api-canary:$(CANARY_VERSION)

eb setenv DJANGO_ENV=canary
eb deploy --label $(CANARY_VERSION)

git tag canary@$(CANARY_VERSION)
Expand All @@ -58,6 +62,8 @@ build-and-push-dev:
docker build -t massenergize/api-dev .
docker tag massenergize/api-dev:latest 202758212688.dkr.ecr.us-east-2.amazonaws.com/massenergize/api-dev:$(DEV_VERSION)
docker push 202758212688.dkr.ecr.us-east-2.amazonaws.com/massenergize/api-dev:$(DEV_VERSION)

eb setenv DJANGO_ENV=dev
eb deploy --label $(DEV_VERSION)

git tag dev@$(DEV_VERSION)
Expand Down
10 changes: 6 additions & 4 deletions src/_main_/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,19 +27,21 @@

# ******** LOAD CONFIG DATA ***********#
# DJANGO_ENV can be passed in through the makefile, with "make start env=local"
DJANGO_ENV = os.environ.get("DJANGO_ENV","remote")
DJANGO_ENV = os.environ.get("DJANGO_ENV", "dev").lower()

# Database selection, development DB unless one of these chosen
IS_PROD = False
IS_CANARY = False
IS_LOCAL = False
IS_PROD = DJANGO_ENV == 'prod'
IS_CANARY = DJANGO_ENV == 'canary'
IS_LOCAL = DJANGO_ENV == 'local'

RUN_SERVER_LOCALLY = IS_LOCAL
RUN_CELERY_LOCALLY = IS_LOCAL

if is_test_mode():
RUN_CELERY_LOCALLY = True



try:
if IS_PROD:
env_path = Path('.') / 'prod.env'
Expand Down
6 changes: 6 additions & 0 deletions src/api/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,3 +37,9 @@

COMMUNITY_NOTIFICATION_TYPES = [USER_EVENTS_NUDGES_FF]

PAGE_SETUP_ESSENTIALS = {
"homepage":{

}
}

abdullai-t marked this conversation as resolved.
Show resolved Hide resolved
3 changes: 2 additions & 1 deletion src/api/handlers/event.py
Original file line number Diff line number Diff line change
Expand Up @@ -64,7 +64,8 @@ def info(self, request):
def copy(self, request):
context: Context = request.context
args: dict = context.args


self.validator.rename("id", "event_id")
self.validator.expect("event_id", int, is_required=True)
args, err = self.validator.verify(args, strict=True)

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

goal_id = args.get('goal_id')
goal_id = args.get('goal_id', args.get('id', None))
goal_info, err = self.service.get_goal_info(goal_id)
if err:
return err
Expand Down
53 changes: 52 additions & 1 deletion src/api/handlers/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
from api.decorators import admins_only, super_admins_only
from database.utils.settings.admin_settings import AdminPortalSettings
from database.utils.settings.user_settings import UserPortalSettings
from concurrent.futures import ThreadPoolExecutor
import requests
from django.urls import reverse


class MiscellaneousHandler(RouteHandler):
Expand All @@ -17,7 +20,7 @@ def __init__(self):

def registerRoutes(self) -> None:
self.add("/menus.remake", self.remake_navigation_menu)
self.add("/menus.list", self.navigation_menu_list)
self.add("/menus.list", self.load_menu_items)
self.add("/data.backfill", self.backfill)
self.add("/data.carbonEquivalency.create", self.create_carbon_equivalency)
self.add("/data.carbonEquivalency.update", self.update_carbon_equivalency)
Expand All @@ -32,6 +35,7 @@ def registerRoutes(self) -> None:
self.add("/settings.list", self.fetch_available_preferences)
self.add("/what.happened", self.fetch_footages)
self.add("/actions.report", self.actions_report)
self.add("/site.load", self.load_essential_initial_site_data)

@admins_only
def fetch_footages(self, request):
Expand Down Expand Up @@ -157,3 +161,50 @@ def authenticateFrontendInTestMode(self, request):
"token", value=token, max_age=24 * 60 * 60, samesite="Strict"
)
return response


def load_essential_initial_site_data(self, request):
context: Context = request.context
args: dict = context.args

self.validator.expect("community_id", is_required=False)
self.validator.expect("subdomain", is_required=False)
self.validator.expect("data", 'str_list', is_required=True)
self.validator.expect("id", is_required=False)

args, err = self.validator.verify(args, strict=True)
if err:
return err

endpoints = args.pop("data", [])

def fetch_data(endpoint):
endpoint = request.build_absolute_uri(endpoint)
response = requests.post(endpoint,data=args)
return response.json()
abdullai-t marked this conversation as resolved.
Show resolved Hide resolved

# Use a ThreadPoolExecutor to make requests to all endpoints concurrently
with ThreadPoolExecutor(max_workers=5) as executor:
results = executor.map(fetch_data, endpoints)

# Convert the results to a dictionary in the format {endpoint: data}
data = {endpoint: result for endpoint, result in zip(endpoints, results)}

return MassenergizeResponse(data=data)


def load_menu_items(self, request):
context: Context = request.context
args: dict = context.args

self.validator.expect("community_id", is_required=False)
self.validator.expect("subdomain", is_required=False)

args, err = self.validator.verify(args, strict=True)
if err:
return MassenergizeResponse(error=err)

data, err = self.service.load_menu_items(context, args)
if err:
return err
return MassenergizeResponse(data=data)
2 changes: 1 addition & 1 deletion src/api/handlers/policy.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ def registerRoutes(self):
def info(self, request):
context: Context = request.context
args: dict = context.args
policy_id = args.pop('policy_id', None)
policy_id = args.pop('policy_id', args.pop('id', None))
policy_info, err = self.service.get_policy_info(policy_id)
if err:
return err
Expand Down
2 changes: 1 addition & 1 deletion src/api/handlers/subscriber.py
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ def registerRoutes(self):
def info(self, request):
context: Context = request.context
args: dict = context.args
subscriber_id = args.pop('subscriber_id', None)
subscriber_id = args.pop('subscriber_id', args.pop('id', None))
if subscriber_id and not isinstance(subscriber_id, int):
subscriber_id = parse_int(subscriber_id)
subscriber_info, err = self.service.get_subscriber_info(subscriber_id)
Expand Down
4 changes: 4 additions & 0 deletions src/api/handlers/vendor.py
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ def registerRoutes(self):
def info(self, request):
context: Context = request.context
args = context.get_request_body()

self.validator.rename("id", "vendor_id")
self.validator.expect("vendor_id", int, is_required=False)

args = rename_field(args, 'vendor_id', 'id')
vendor_info, err = self.service.get_vendor_info(context, args)
if err:
Expand Down
17 changes: 17 additions & 0 deletions src/api/services/misc.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,3 +141,20 @@ def authenticateFrontendInTestMode(self, args):
return None, CustomMassenergizeError(str(err))
client = Client()
return signinAs(client, user), None


# def load_essential_initial_site_data(self,context, args):
# res, err = self.store.load_essential_initial_site_data(context,args)
# if err:
# return None, err
#
# return res, None
abdullai-t marked this conversation as resolved.
Show resolved Hide resolved

def load_menu_items(self,context, args):
res, err = self.store.load_menu_items(context,args)
if err:
return None, err

return res, None


2 changes: 1 addition & 1 deletion src/api/store/community.py
Original file line number Diff line number Diff line change
Expand Up @@ -1366,7 +1366,7 @@ def list_communities_feature_flags(self, context, args) -> Tuple[list, MassEnerg
(Q(audience=FeatureFlagConstants().for_all_except()) & ~Q(communities__in=communities))
).exclude(expires_on__lt=datetime.now()).prefetch_related('communities')

return feature_flags, None
return feature_flags.distinct(), None

except Exception as e:
return None, CustomMassenergizeError(str(e))
Expand Down
117 changes: 91 additions & 26 deletions src/api/store/misc.py
Original file line number Diff line number Diff line change
@@ -1,36 +1,21 @@
from typing import Tuple

from sentry_sdk import capture_message

from _main_.utils.context import Context
from _main_.utils.footage.spy import Spy
from api.tests.common import createUsers
from database.models import (
Action,
Vendor,
Subdomain,
Event,
Community,
Menu,
Team,
TeamMember,
CommunityMember,
RealEstateUnit,
CommunityAdminGroup,
UserProfile,
Data,
TagCollection,
UserActionRel,
Data,
Location,
HomePageSettings,
)
from _main_.utils.massenergize_errors import (
CustomMassenergizeError,
InvalidResourceError,
MassEnergizeAPIError,
)
from _main_.utils.context import Context
from api.tests.common import createUsers
from api.utils.api_utils import get_viable_menu_items
from database.models import Action, CarbonEquivalency, Community, CommunityAdminGroup, CommunityMember, Data, Event, \
HomePageSettings, Location, Menu, RealEstateUnit, Subdomain, TagCollection, Team, TeamMember, UserActionRel, \
UserProfile, Vendor
from database.utils.common import json_loader
from database.models import CarbonEquivalency
from .utils import find_reu_community, split_location_string, check_location
from sentry_sdk import capture_message
from typing import Tuple
from .utils import check_location, find_reu_community, get_community, split_location_string


class MiscellaneousStore:
Expand Down Expand Up @@ -492,3 +477,83 @@ def list_commonly_used_icons(self):
sorted_keys = sorted(common_icons, key=common_icons.get, reverse=True)
for key in sorted_keys:
print(str(key) + ": " + str(common_icons[key]))


# def load_essential_initial_site_data(self, context, args):
# try:
# page = args.get("page", None)
# subdonain = args.get("subdomain", None)
# community_id = args.get("community_id", None)
# id = args.get("id", None)
#
# if not subdonain and not community_id:
# return None, CustomMassenergizeError("No community or subdomain provided")
#
# if not page:
# return None, CustomMassenergizeError("No page provided")
#
# community, _ = get_community(community_id=community_id, subdomain=subdonain)
# if not community:
# return None, CustomMassenergizeError("Community not found")
#
# page_settings = {
# "home_page_settings": HomePageSettings.objects.filter(community=community).first(),
# "actions_page_settings": ActionsPageSettings.objects.filter(community=community).first(),
# "events_page_settings": EventsPageSettings.objects.filter(community=community).first(),
# "vendors_page_settings": VendorsPageSettings.objects.filter(community=community).first(),
# "about_us_page_settings": AboutUsPageSettings.objects.filter(community=community).first(),
abdullai-t marked this conversation as resolved.
Show resolved Hide resolved
# "testimonials_page_settings": TestimonialsPageSettings.objects.filter(community=community).first(),
# "teams_page_settings": TeamsPageSettings.objects.filter(community=community).first(),
# "contact_us_page_settings": ContactUsPageSettings.objects.filter(community=community).first(),
# "impact_page_settings": ImpactPageSettings.objects.filter(community=community).first(),
# }
#
# data = {}
#
# page_func_map = {
# "homepage": load_homepage_data,
# "actions": load_actions_data,
# "events": load_events_data,
# "vendors": load_vendors_data,
# "about": load_about_data,
# "testimonials": load_testimonials_data,
# "one_vendor": load_one_vendor_data,
# "impact": load_impact_data,
# "aboutus": load_aboutus_data,
# "contactus": load_contactus_data,
# "teams": load_teams_data,
# "one_team": load_one_team_data,
# "one_action": load_one_action_data,
# "one_event": load_one_event_data,
# "one_testimonial": load_one_testimonial_data,
# "profile": load_profile_data,
# "settings": load_settings_data,
# "policies": load_policies_data,
# }
# func = page_func_map.get(page)
# if func:
# data = func(context, args, community, id, page_settings)
#
# return data, None
# except Exception as e:
# return None, CustomMassenergizeError(e)

def load_menu_items(self, context, args):
try:
page = args.get("page", None)
subdonain = args.get("subdomain", None)
community_id = args.get("community_id", None)
user_id = args.get("user_id", None)

if not subdonain and not community_id:
return None, CustomMassenergizeError("No community or subdomain provided")

community, _ = get_community(community_id=community_id, subdomain=subdonain)
if not community:
return None, CustomMassenergizeError("Community not found")

menu = get_viable_menu_items(community)

return menu, None
except Exception as e:
return None, CustomMassenergizeError(e)
Loading
Loading