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

Fix/delete outdated favorites v2 #367

Merged
merged 10 commits into from
Jun 9, 2020
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 2.0.13 on 2020-05-27 12:38

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('available_positions', '0002_availablepositiondesignation'),
]

operations = [
migrations.AddField(
model_name='availablepositionfavorite',
name='archived',
field=models.BooleanField(default=False),
),
]
1 change: 1 addition & 0 deletions talentmap_api/available_positions/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ class AvailablePositionFavorite(StaticRepresentationModel):

cp_id = models.TextField(null=False)
user = models.ForeignKey('user_profile.UserProfile', null=False, on_delete=models.DO_NOTHING, help_text="The user to which this favorite belongs")
archived = models.BooleanField(default=False)

class Meta:
managed = True
Expand Down
17 changes: 14 additions & 3 deletions talentmap_api/available_positions/views/available_position.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
from django.shortcuts import get_object_or_404
from django.http import QueryDict

from django.conf import settings

from rest_framework.viewsets import ReadOnlyModelViewSet, GenericViewSet
from rest_framework.permissions import IsAuthenticated, IsAuthenticatedOrReadOnly
from rest_framework.views import APIView
Expand All @@ -21,6 +23,8 @@
import talentmap_api.fsbid.services.projected_vacancies as pvservices
import talentmap_api.fsbid.services.common as comservices

FAVORITES_LIMIT = settings.FAVORITES_LIMIT

class AvailablePositionsFilter():
declared_filters = [
"exclude_available",
Expand Down Expand Up @@ -49,10 +53,11 @@ def get(self, request, *args, **kwargs):
Return a list of all of the user's favorite available positions.
"""
user = UserProfile.objects.get(user=self.request.user)
aps = AvailablePositionFavorite.objects.filter(user=user).values_list("cp_id", flat=True)
aps = AvailablePositionFavorite.objects.filter(user=user, archived=False).values_list("cp_id", flat=True)
limit = request.query_params.get('limit', 15)
page = request.query_params.get('page', 1)
if len(aps) > 0:
services.archive_favorites(aps, request)
scott062 marked this conversation as resolved.
Show resolved Hide resolved
pos_nums = ','.join(aps)
return Response(services.get_available_positions(QueryDict(f"id={pos_nums}&limit={limit}&page={page}"),
request.META['HTTP_JWT'],
Expand Down Expand Up @@ -132,8 +137,14 @@ def put(self, request, pk, format=None):
Marks the available position as a favorite
'''
user = UserProfile.objects.get(user=self.request.user)
AvailablePositionFavorite.objects.get_or_create(user=user, cp_id=pk)
return Response(status=status.HTTP_204_NO_CONTENT)
aps = AvailablePositionFavorite.objects.filter(user=user, archived=False).values_list("cp_id", flat=True)
services.archive_favorites(aps, request)
aps_after_archive = AvailablePositionFavorite.objects.filter(user=user, archived=False).values_list("cp_id", flat=True)
if len(aps_after_archive) >= FAVORITES_LIMIT:
return Response({"limit": FAVORITES_LIMIT}, status=status.HTTP_507_INSUFFICIENT_STORAGE)
else:
AvailablePositionFavorite.objects.get_or_create(user=user, cp_id=pk)
return Response(status=status.HTTP_204_NO_CONTENT)

def delete(self, request, pk, format=None):
'''
Expand Down
3 changes: 3 additions & 0 deletions talentmap_api/fsbid/apps.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,6 @@

class FsbidConfig(AppConfig):
name = 'fsbid'

def ready(self):
import fsbid.signals
40 changes: 38 additions & 2 deletions talentmap_api/fsbid/services/available_positions.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,17 +8,21 @@

from django.conf import settings
from django.db.models import Q
from django.http import HttpResponse
from django.http import HttpResponse, QueryDict
from django.utils.encoding import smart_str
from django.core.exceptions import ObjectDoesNotExist

from talentmap_api.common.common_helpers import ensure_date, safe_navigation, validate_values
from talentmap_api.bidding.models import BidCycle
from talentmap_api.available_positions.models import AvailablePositionDesignation
from talentmap_api.available_positions.models import AvailablePositionDesignation, AvailablePositionFavorite

import talentmap_api.fsbid.services.common as services

import logging
logger = logging.getLogger(__name__)

API_ROOT = settings.FSBID_API_URL
FAVORITES_LIMIT = settings.FAVORITES_LIMIT

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -363,3 +367,35 @@ def convert_all_query(query):
but FP, OP, or HS will get removed from query
'''
return (convert_ap_query(query, ["FP", "OP", "HS"]))

def archive_favorites(aps, request, favoritesLimit=FAVORITES_LIMIT):
fav_length = len(aps)
if fav_length >= favoritesLimit or fav_length == round(favoritesLimit/2):
# Pos nums is string to pass correctly to services url
pos_nums = ','.join(aps)
# List favs is list of integers instead of strings for comparison
list_favs = list(map(lambda x: int(x), aps))
# Ids from fsbid that have filled position code (double checks they are invalid)
returned_ids = get_ap_favorite_ids(QueryDict(f"id={pos_nums}&limit=999999&page=1&cps_codes=FP"), request.META['HTTP_JWT'], f"{request.scheme}://{request.get_host()}")
# Need to determine which ids need to be archived using comparison of lists above
outdated_ids = []
for fav_id in list_favs:
if fav_id in returned_ids:
outdated_ids.append(fav_id)
if len(outdated_ids) > 0:
AvailablePositionFavorite.objects.filter(cp_id__in=outdated_ids).update(archived=True)

def get_ap_favorite_ids(query, jwt_token, host=None):
return services.send_get_request(
"availablePositions",
query,
convert_up_query,
jwt_token,
fsbid_favorites_to_talentmap_favorites_ids,
get_available_positions_count,
"/api/v1/fsbid/available_positions/",
host
).get('results')

def fsbid_favorites_to_talentmap_favorites_ids(ap):
return ap.get("cp_id", None)
38 changes: 36 additions & 2 deletions talentmap_api/fsbid/services/projected_vacancies.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@

from django.conf import settings
from django.core.exceptions import ObjectDoesNotExist
from django.http import HttpResponse
from django.http import HttpResponse, QueryDict
from django.utils.encoding import smart_str

from talentmap_api.common.common_helpers import ensure_date, safe_navigation
import talentmap_api.fsbid.services.common as services
from talentmap_api.projected_vacancies.models import ProjectedVacancyFavorite

API_ROOT = settings.FSBID_API_URL
FAVORITES_LIMIT = settings.FAVORITES_LIMIT

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -240,4 +242,36 @@ def convert_pv_query(query):
"fv_request_params.tod_codes2": services.convert_multi_value(query.get("position__post__tour_of_duty__code__in-tandem")),
"fv_request_params.skills2": services.convert_multi_value(query.get("position__skill__code__in-tandem")),
}
return urlencode({i: j for i, j in values.items() if j is not None}, doseq=True, quote_via=quote)
return urlencode({i: j for i, j in values.items() if j is not None}, doseq=True, quote_via=quote)

def archive_favorites(pvs, request, favoritesLimit=FAVORITES_LIMIT):
favs_length = len(pvs)
if favs_length >= favoritesLimit or favs_length == round(favoritesLimit/2):
# Pos nums is string to pass correctly to services url
pos_nums = ','.join(pvs)
# List favs is list of integers instead of strings for comparison
list_favs = list(map(lambda x: int(x), pvs))
# Valid resulting ids from fsbid
returned_ids = get_pv_favorite_ids(QueryDict(f"id={pos_nums}&limit=999999&page=1"), request.META['HTTP_JWT'], f"{request.scheme}://{request.get_host()}")
# Need to determine which ids need to be archived using comparison of lists above
outdated_ids = []
for fav_id in list_favs:
if fav_id not in returned_ids:
outdated_ids.append(fav_id)
if len(outdated_ids) > 0:
ProjectedVacancyFavorite.objects.filter(fv_seq_num__in=outdated_ids).update(archived=True)

def get_pv_favorite_ids(query, jwt_token, host=None):
return services.send_get_request(
"futureVacancies",
query,
convert_pv_query,
jwt_token,
fsbid_favorites_to_talentmap_favorites_ids,
get_projected_vacancies_count,
"/api/v1/fsbid/projected_vacancies/",
host
).get('results')

def fsbid_favorites_to_talentmap_favorites_ids(pv):
return pv.get("fv_seq_num", None)
1 change: 0 additions & 1 deletion talentmap_api/fsbid/views/projected_vacancies.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,6 @@ def get(self, request, pk):
result = services.get_projected_vacancy(pk, request.META['HTTP_JWT'])
if result is None:
return Response(status=status.HTTP_404_NOT_FOUND)

return Response(result)

class FSBidProjectedVacanciesCSVView(BaseView):
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 2.0.13 on 2020-05-27 12:39

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('projected_vacancies', '0004_remove_projectedvacancyfavorite__string_representation'),
]

operations = [
migrations.AddField(
model_name='projectedvacancyfavorite',
name='archived',
field=models.BooleanField(default=False),
),
]
1 change: 1 addition & 0 deletions talentmap_api/projected_vacancies/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ class ProjectedVacancyFavorite(models.Model):

fv_seq_num = models.TextField(null=False)
user = models.ForeignKey('user_profile.UserProfile', null=False, on_delete=models.DO_NOTHING, help_text="The user to which this favorite belongs")
archived = models.BooleanField(default=False)

class Meta:
managed = True
Expand Down
17 changes: 13 additions & 4 deletions talentmap_api/projected_vacancies/views/projected_vacancy.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

from django.shortcuts import render
from django.http import QueryDict
from django.conf import settings

from rest_framework.viewsets import ReadOnlyModelViewSet
from rest_framework.permissions import IsAuthenticated, IsAuthenticatedOrReadOnly
Expand All @@ -18,6 +19,7 @@

import talentmap_api.fsbid.services.projected_vacancies as services

FAVORITES_LIMIT = settings.FAVORITES_LIMIT

class ProjectedVacancyFavoriteListView(APIView):

Expand All @@ -36,10 +38,11 @@ def get(self, request, *args, **kwargs):
Return a list of all of the user's favorite projected vacancies.
"""
user = UserProfile.objects.get(user=self.request.user)
pvs = ProjectedVacancyFavorite.objects.filter(user=user).values_list("fv_seq_num", flat=True)
pvs = ProjectedVacancyFavorite.objects.filter(user=user, archived=False).values_list("fv_seq_num", flat=True)
limit = request.query_params.get('limit', 12)
page = request.query_params.get('page', 1)
if len(pvs) > 0:
services.archive_favorites(pvs, request)
pos_nums = ','.join(pvs)
return Response(services.get_projected_vacancies(QueryDict(f"id={pos_nums}&limit={limit}&page={page}"),
request.META['HTTP_JWT'],
Expand Down Expand Up @@ -87,9 +90,15 @@ def put(self, request, pk, format=None):
Marks the projected vacancy as a favorite
'''
user = UserProfile.objects.get(user=self.request.user)
pvf = ProjectedVacancyFavorite(user=user, fv_seq_num=pk)
pvf.save()
return Response(status=status.HTTP_204_NO_CONTENT)
pvs = ProjectedVacancyFavorite.objects.filter(user=user, archived=False).values_list("fv_seq_num", flat=True)
services.archive_favorites(pvs, request)
pvs_after_archive = ProjectedVacancyFavorite.objects.filter(user=user, archived=False).values_list("fv_seq_num", flat=True)
if len(pvs_after_archive) >= FAVORITES_LIMIT:
return Response({"limit": FAVORITES_LIMIT}, status=status.HTTP_507_INSUFFICIENT_STORAGE)
else:
pvf = ProjectedVacancyFavorite(user=user, fv_seq_num=pk)
pvf.save()
return Response(status=status.HTTP_204_NO_CONTENT)

def delete(self, request, pk, format=None):
'''
Expand Down
2 changes: 2 additions & 0 deletions talentmap_api/settings.py
Original file line number Diff line number Diff line change
Expand Up @@ -522,3 +522,5 @@ def config_settings_loader(request):
},
},
}

FAVORITES_LIMIT = 50