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

Release/uat/3.7.0 #215

Merged
merged 81 commits into from
Aug 10, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
81 commits
Select commit Hold shift + click to select a range
a9a0bf3
Revert adding azure-monitor-opentelemetry==1.0.0b13 to resolve No mod…
gkalomalos Jun 22, 2023
6eb8a49
updated empty value type (#141)
ladeniva2 Jun 22, 2023
b96f005
Feature/160752/stages phases (#142)
Alexa-Laf Jun 22, 2023
51f573f
updated styles to work on all browsers (#143)
ladeniva2 Jun 22, 2023
f1888a7
feat/Add azure-monitor-opentelemetry to requirements
gkalomalos Jun 22, 2023
3434f2e
feat/Add configure_azure_monitor to settings.py
gkalomalos Jun 22, 2023
c011d98
chore/Remove configure_azure_monitor and implement older approach to …
gkalomalos Jun 22, 2023
0bf2a32
chore/Remove opentelemetry from settings.py
gkalomalos Jun 22, 2023
30171be
chore/Code cleanup
gkalomalos Jun 23, 2023
b09c6cc
Dev 157615 160826 162116 163295 163762 164563 (#144)
gkalomalos Jun 23, 2023
7e6ba8f
Feature/163742/enable ootb monitoring capabilities (#146)
gkalomalos Jun 26, 2023
8c40f81
chore/Change configure_azure_monitor signature to include named argument
gkalomalos Jun 26, 2023
85e2c4b
feat/Change userprofile list to autocomplete field (#145)
gkalomalos Jun 27, 2023
30e56b7
rename stage_name and phase_name to stage_label and phase_label (#147)
Alexa-Laf Jun 27, 2023
efaaf0b
feature/161336/initiatives-by-stage-board added stage table and tabl…
ladeniva2 Jun 27, 2023
2ed8b75
feat/Switch nextLink to deltaLink mechanism
gkalomalos Jun 27, 2023
bf6e208
feat/Add get and save last delta link mechanism
gkalomalos Jun 27, 2023
da0d89e
chore/Refactor delta link generation and store method
gkalomalos Jun 28, 2023
8bbb50f
Feature/refactor aad user fetch and update mechanism (#149)
gkalomalos Jun 28, 2023
e946458
chore/Add migration file for deltalink
gkalomalos Jun 28, 2023
8c317f6
Merge branch 'feature/refactor-aad-user-fetch-and-update-mechanism' i…
gkalomalos Jun 28, 2023
6157874
chore/Add log statements to debug deltalink response
gkalomalos Jun 28, 2023
46a5dcf
chore/Remove redundant log statements
gkalomalos Jun 28, 2023
6d2f2fc
chore/Refactor deltalinks and logger
gkalomalos Jun 28, 2023
2926ab5
Revert commits 2ed8b75c01bd61b4a100830931c58c340ab6f98c to 46a5dcfae4…
gkalomalos Jun 28, 2023
b7a21b5
Merge branch 'tst' into dev
gkalomalos Jun 28, 2023
1cdfea7
Bugfix/163402/dashboarding system error (#150)
mgaliatsatou Jun 28, 2023
e87138c
Merge dev to tst (#152)
gkalomalos Jun 28, 2023
142cb2d
feat/Add delta to graph url
gkalomalos Jun 28, 2023
82acc7c
chore/Remove redundant logging statements
gkalomalos Jun 29, 2023
6164396
Rollback to pre-deltaLink mechanism
gkalomalos Jun 29, 2023
f977532
chore/Remove redundant files
gkalomalos Jun 29, 2023
2aac887
Merge branch 'tst' of https://github.com/unicef/invent into dev
gkalomalos Jun 29, 2023
681c73c
Merge dev to tst (#154)
gkalomalos Jun 30, 2023
f4128d2
Merge branch 'uat' into tst
gkalomalos Jun 30, 2023
c895100
Performance optimization (#156)
gkalomalos Jun 30, 2023
a84130a
Merge dev to tst (#157)
gkalomalos Jun 30, 2023
19d2bfa
Merge branch 'dev' into tst
ladeniva2 Jun 30, 2023
6770f50
add autocomplete field managers (#159)
Alexa-Laf Jul 3, 2023
4e834cd
add autocomplete field managers (#159) (#160)
Alexa-Laf Jul 3, 2023
490a00a
chore/Remove DeltaLink model
gkalomalos Jul 3, 2023
380da47
Merge dev to tst (#163)
gkalomalos Jul 5, 2023
b642fc1
Added country inventory link button on homepage (#164)
ladeniva2 Jul 5, 2023
a8c2d9a
added height select switch, made table height expandable (#165)
ladeniva2 Jul 5, 2023
10586d5
add job title and section to export files (#162)
Alexa-Laf Jul 5, 2023
e931a47
Bugfix/163755/country link inventory (#166)
ladeniva2 Jul 5, 2023
a5cc7be
Feature/165200/select sectors appear phase stage board (#167)
ladeniva2 Jul 5, 2023
875ba5c
replace section name to department (#168)
Alexa-Laf Jul 6, 2023
392cc2e
link changed from button to link (#169)
ladeniva2 Jul 7, 2023
ccb40d4
changed project data fallback for projectBar and breadcrumps (#170)
ladeniva2 Jul 7, 2023
8db1624
id correction (#171)
ladeniva2 Jul 10, 2023
e13cfe1
users list timing loading fix and data refresh for initiatives (#172)
ladeniva2 Jul 11, 2023
caebf88
updated button ui and added text to link (#177)
ladeniva2 Jul 12, 2023
cb5f06e
Merge dev to tst (#179)
gkalomalos Jul 12, 2023
3451e81
UI changes
ladeniva2 Jul 19, 2023
21a7a9f
UI changes (#182)
ladeniva2 Jul 19, 2023
4fffef0
Updated breadcrumbs My Initiatives to Initiatives link to inventory l…
ladeniva2 Jul 19, 2023
04de106
Merge branch 'tst' into dev
ladeniva2 Jul 19, 2023
7c4f600
Bugfix/130138/admin export users fails (#184)
mgaliatsatou Jul 20, 2023
cb96590
chore/Remove unnecessary commands from startup_actions
gkalomalos Jul 20, 2023
4fe058c
chore/Silence opentelemetry logs in dev
gkalomalos Jul 21, 2023
26c9544
chore/Remove unnecessary log statements
gkalomalos Jul 21, 2023
afe21e3
Feature/160750/make end phases config (#186)
Alexa-Laf Jul 24, 2023
d4bc7fd
Merge branch 'feature/165332/improvements-to-co-boards' into tst
ladeniva2 Jul 24, 2023
8310639
Count last phase always as end phase (#187)
ladeniva2 Jul 25, 2023
8fd53f3
Bugfix/increase dev test coverage (#190)
Alexa-Laf Jul 28, 2023
eb4a617
Revert "Count last phase always as end phase"
ladeniva2 Jul 28, 2023
1087a88
Revert "dynamically get end phases and hide them in phases board"
ladeniva2 Jul 28, 2023
08f3a3f
remove tests for discontinued and remove duplicate class (#193)
Alexa-Laf Jul 31, 2023
d4ca0fe
Deployment to test environment (#194)
Alexa-Laf Jul 31, 2023
b62df5a
added link to country in initiatives published view
ladeniva2 Aug 1, 2023
60a320b
updated data test id, added link to inventory countries column
ladeniva2 Aug 1, 2023
9ad19e7
hide initiatives that have completed an end phase (#196)
ladeniva2 Aug 2, 2023
eebf1a3
Feature/168436/add links from country to co pages (#195)
ladeniva2 Aug 2, 2023
c883729
remove last phase, hide some comments
ladeniva2 Aug 2, 2023
104f952
remove last phase, hide some comments (#197)
ladeniva2 Aug 2, 2023
4e9af6f
updated column count when sectors filtered
ladeniva2 Aug 2, 2023
f8b0a0b
Merge branch 'feature/168436/add-links-from-country-to-co-pages' into…
ladeniva2 Aug 7, 2023
9b1b0d5
Merge branch 'feature/168540/update-column-count-when-sectors-filtere…
ladeniva2 Aug 7, 2023
2d501a6
Merge branch 'feature/168529/always-hide-last-phase-column' into rele…
ladeniva2 Aug 7, 2023
412eaf8
Merge branch 'release/3.7.0' into release/uat/3.7.0
ladeniva2 Aug 10, 2023
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
3 changes: 3 additions & 0 deletions django/core/admin/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ class UserProfileInline(admin.StackedInline):


class CustomUserAdmin(ExportActionMixin, UserAdmin):
from import_export_celery.admin_actions import create_export_job_action
create_export_job_action.short_description = "Generate export in the background"
actions = (create_export_job_action,)
list_display = ('userprofile', 'country', 'type', 'organisation', 'is_staff', 'is_superuser')
search_fields = ('userprofile__name', 'email', 'userprofile__country__name', 'userprofile__organisation__name')
inlines = (UserProfileInline,)
Expand Down
6 changes: 4 additions & 2 deletions django/project/management/commands/add_taxonomies.py
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,12 @@ def handle(self, *args, **options):

for block_name in data:
if block_name in self.data_model_map:
self.fill_named_model(data[block_name], self.data_model_map[block_name])
self.fill_named_model(
data[block_name], self.data_model_map[block_name])
elif block_name == 'Currency':
self.fill_currencies(data[block_name])
elif block_name in self.nonmodel_blocks:
pp.pprint(f"Warning: need to check {block_name} by hand as it's non-model")
pp.pprint(
f"Warning: need to check {block_name} by hand as it's non-model")
else: # pragma: no cover
pp.pprint(f"Warning: unhandled block name: {block_name}")
Original file line number Diff line number Diff line change
Expand Up @@ -7,10 +7,6 @@ def update_translation_fields(apps, schema_editor):
call_command('update_translation_fields')


def add_taxonomies(apps, schema_editor):
call_command('add_taxonomies', '--verbosity', 0)


def rebuild_search(apps, schema_editor):
call_command('rebuild_search')

Expand All @@ -31,8 +27,8 @@ class Migration(migrations.Migration):
]

operations = [
migrations.RunPython(update_translation_fields, reverse_code=migrations.RunPython.noop),
migrations.RunPython(add_taxonomies, reverse_code=migrations.RunPython.noop),
# migrations.RunPython(rebuild_search, reverse_code=migrations.RunPython.noop),
migrations.RunPython(reorder_stages, reverse_code=migrations.RunPython.noop),
migrations.RunPython(update_translation_fields,
reverse_code=migrations.RunPython.noop),
migrations.RunPython(
reorder_stages, reverse_code=migrations.RunPython.noop),
]
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 2.1 on 2023-07-20 18:43

from django.db import migrations, models


class Migration(migrations.Migration):

dependencies = [
('project', '0105_delete_deltalink'),
]

operations = [
migrations.AddField(
model_name='stage',
name='completion_marks_an_initiative_as_inactive',
field=models.BooleanField(default=False, help_text='When this phase is marked as completed (with an end date) it means that the initiative is no longer active.<br>It will not move automatically to a following phase, but will stay in this phase.'),
),
]
18 changes: 18 additions & 0 deletions django/project/migrations/0107_reorder_stages.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
# Generated by Django 2.1 on 2023-07-20 18:43
from django.core.management import call_command
from django.db import migrations


def add_taxonomies(apps, schema_editor):
call_command('add_taxonomies', '--verbosity', 0)


class Migration(migrations.Migration):
dependencies = [
('project', '0106_stage_completion_marks_an_initiative_as_inactive'),
]

operations = [
migrations.RunPython(
add_taxonomies, reverse_code=migrations.RunPython.noop),
]
39 changes: 20 additions & 19 deletions django/project/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -1013,6 +1013,8 @@ class Stage(InvalidateCacheMixin, ExtendedNameOrderedSoftDeletedModel):
name = models.CharField(max_length=128)
order = models.PositiveSmallIntegerField(default=0, blank=True, null=True)
tooltip = models.CharField(max_length=256, blank=True, null=True)
completion_marks_an_initiative_as_inactive = models.BooleanField(
help_text="When this phase is marked as completed (with an end date) it means that the initiative is no longer active.<br>It will not move automatically to a following phase, but will stay in this phase.", default=False)

class Meta:
ordering = ["order", "name"]
Expand All @@ -1022,37 +1024,36 @@ class Meta:
def __str__(self): # pragma: no cover
return self.name

@classmethod
def get_discontinued(cls):
"""
Hardcoded for now. Object with this name must exist in the DB to work.
"""
return cls.objects.get(name="Discontinued")

@classmethod
def calc_current_phase(cls, stages: List[Dict]):
discontinued_id = cls.get_discontinued().id
all_stages = list(cls.objects.order_by(
"order").values_list("id", flat=True))
one_before_discontinued_id = all_stages[all_stages.index(
discontinued_id) - 1]

if not stages: # when no phases are selected the current phase is the first one
return all_stages[0]

stage_ids = [stage["id"] for stage in stages]
# get the completed phases of the initiative and order them
selected_stages = cls.objects.filter(
id__in=stage_ids).order_by("order")
# get the last phase from initiative's completed phases
last_stage = selected_stages.last()

if last_stage.id == discontinued_id:
current = discontinued_id
elif last_stage.id == one_before_discontinued_id:
current = last_stage.id
elif last_stage.id == all_stages[-1]:
current = last_stage.id
else:
current = all_stages[all_stages.index(last_stage.id) + 1]
# apply the business requirements
if not last_stage.completion_marks_an_initiative_as_inactive: # selected phase's checkbox unchecked
# compute if there are already previous completed end phases (checkbox=checked)
completed_stages = selected_stages.filter(
completion_marks_an_initiative_as_inactive=True)
if completed_stages: # if there completed end phases
current = last_stage.id
else: # if there are not completed end phases
if last_stage.id != all_stages[-1]: # not the last in list
current = all_stages[all_stages.index(
last_stage.id) + 1] # get the next phase
else: # the last in list
current = last_stage.id # set this phase as current
else: # selected phase's checkbox checked
current = last_stage.id # set this phase as current

return current


Expand Down
138 changes: 70 additions & 68 deletions django/project/tests/project_stage_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@

from project.models import Stage
from project.tests.setup import SetupTests
from django.test import TestCase
from project.views import ProjectPublicViewSet


class ProjectStageTests(SetupTests):
Expand All @@ -16,15 +18,19 @@ def test_project_stages(self):
data = copy.deepcopy(self.project_data)

data['project']['name'] = 'Test Project 100'
data['project']['start_date'] = str((now - timezone.timedelta(days=10)).date())
data['project']['end_date'] = str((now - timezone.timedelta(days=1)).date())
data['project']['start_date'] = str(
(now - timezone.timedelta(days=10)).date())
data['project']['end_date'] = str(
(now - timezone.timedelta(days=1)).date())
data['project']['end_date_note'] = "note for end date"
del data['project']['stages']

# create project
url = reverse("project-create", kwargs={"country_office_id": self.country_office.id})
url = reverse("project-create",
kwargs={"country_office_id": self.country_office.id})
response = self.test_user_client.post(url, data, format="json")
self.assertEqual(response.status_code, status.HTTP_201_CREATED, response.json())
self.assertEqual(response.status_code,
status.HTTP_201_CREATED, response.json())

project_id = response.json()['id']
self.assertIn("end_date_note", response.json()['draft'])
Expand All @@ -41,8 +47,10 @@ def test_project_stages(self):
url = reverse("project-draft", kwargs={"project_id": project_id,
"country_office_id": self.country_office.id})
response = self.test_user_client.put(url, data, format="json")
self.assertEqual(response.status_code, status.HTTP_400_BAD_REQUEST, response.json())
self.assertEqual(response.json(), {'project': {'stages': [{'date': ['This field may not be null.']}]}})
self.assertEqual(response.status_code,
status.HTTP_400_BAD_REQUEST, response.json())
self.assertEqual(response.json(), {'project': {'stages': [
{'date': ['This field may not be null.']}]}})

stages = Stage.objects.all()
# add stages
Expand All @@ -68,7 +76,8 @@ def test_project_stages(self):
url = reverse("project-draft", kwargs={"project_id": project_id,
"country_office_id": self.country_office.id})
response = self.test_user_client.put(url, data, format="json")
self.assertEqual(response.status_code, status.HTTP_200_OK, response.json())
self.assertEqual(response.status_code,
status.HTTP_200_OK, response.json())
resp_data = response.json()
self.assertIn('stages', resp_data['draft'])
self.assertEqual(len(resp_data['draft']['stages']), 3)
Expand All @@ -78,7 +87,8 @@ def test_project_stages(self):
url = reverse("project-publish", kwargs={"project_id": project_id,
"country_office_id": self.country_office.id})
response = self.test_user_client.put(url, data, format="json")
self.assertEqual(response.status_code, status.HTTP_200_OK, response.json())
self.assertEqual(response.status_code,
status.HTTP_200_OK, response.json())
resp_data = response.json()
self.assertNotIn('stages', resp_data['draft'])
self.assertIn("end_date_note", response.json()['draft'])
Expand All @@ -88,7 +98,8 @@ def test_project_stages(self):
url = reverse("project-publish", kwargs={"project_id": project_id,
"country_office_id": self.country_office.id})
response = self.test_user_client.put(url, data, format="json")
self.assertEqual(response.status_code, status.HTTP_200_OK, response.json())
self.assertEqual(response.status_code,
status.HTTP_200_OK, response.json())
resp_data = response.json()
self.assertIn('stages', resp_data['draft'])
self.assertEqual(len(resp_data['draft']['stages']), 3)
Expand All @@ -102,62 +113,13 @@ def test_stage_list(self):

url = reverse("get-project-structure")
response = self.test_user_client.get(url, format="json")
self.assertEqual(response.status_code, status.HTTP_200_OK, response.json())
self.assertEqual(response.status_code,
status.HTTP_200_OK, response.json())
data = response.json()['stages']
self.assertEqual(data[0]['id'], stage_b.id)
self.assertEqual(data[1]['id'], stage_a.id)
self.assertEqual(data[2]['id'], stage_c.id)

def test_current_phase_discontinued(self):
now = timezone.now()
data = copy.deepcopy(self.project_data)
stage_1 = Stage.objects.all()[0]
stage_discontinued = Stage.objects.get(name='Discontinued')
# add stages
data['project']['stages'] = [
{
'id': stage_1.id,
'date': str((now - timezone.timedelta(days=10)).date()),
'note': 'preparation note'
},
{
'id': stage_discontinued.id,
'date': str((now - timezone.timedelta(days=7)).date()),
'note': 'analysis note'
}
]

url = reverse("project-create", kwargs={"country_office_id": self.country_office.id})
response = self.test_user_client.post(url, data, format="json")
self.assertEqual(response.status_code, status.HTTP_201_CREATED, response.json())
self.assertEqual(response.json()['draft']['current_phase'], stage_discontinued.id)

def test_current_phase_one_before_discontinued(self):
now = timezone.now()
data = copy.deepcopy(self.project_data)
stage_1 = Stage.objects.all()[0]
discontinued_id = Stage.objects.get(name='Discontinued').id
all_stages = list(Stage.objects.order_by('order').values_list('id', flat=True))
one_before_discontinued_id = all_stages[all_stages.index(discontinued_id) - 1]
# add stages
data['project']['stages'] = [
{
'id': stage_1.id,
'date': str((now - timezone.timedelta(days=10)).date()),
'note': 'preparation note'
},
{
'id': one_before_discontinued_id,
'date': str((now - timezone.timedelta(days=7)).date()),
'note': 'analysis note'
}
]

url = reverse("project-create", kwargs={"country_office_id": self.country_office.id})
response = self.test_user_client.post(url, data, format="json")
self.assertEqual(response.status_code, status.HTTP_201_CREATED, response.json())
self.assertEqual(response.json()['draft']['current_phase'], one_before_discontinued_id)

def test_current_phase_normal_case(self):
now = timezone.now()
data = copy.deepcopy(self.project_data)
Expand All @@ -176,19 +138,24 @@ def test_current_phase_normal_case(self):
}
]

url = reverse("project-create", kwargs={"country_office_id": self.country_office.id})
url = reverse("project-create",
kwargs={"country_office_id": self.country_office.id})
response = self.test_user_client.post(url, data, format="json")
self.assertEqual(response.status_code, status.HTTP_201_CREATED, response.json())
self.assertEqual(response.json()['draft']['current_phase'], stages[2].id)
self.assertEqual(response.status_code,
status.HTTP_201_CREATED, response.json())
self.assertEqual(response.json()['draft']
['current_phase'], stages[2].id)

def test_current_phase_no_phase_selected(self):
data = copy.deepcopy(self.project_data)
stage_1 = Stage.objects.order_by('order').first()
data['project']['stages'] = []

url = reverse("project-create", kwargs={"country_office_id": self.country_office.id})
url = reverse("project-create",
kwargs={"country_office_id": self.country_office.id})
response = self.test_user_client.post(url, data, format="json")
self.assertEqual(response.status_code, status.HTTP_201_CREATED, response.json())
self.assertEqual(response.status_code,
status.HTTP_201_CREATED, response.json())
self.assertEqual(response.json()['draft']['current_phase'], stage_1.id)

def test_current_phase_is_last_phase(self):
Expand All @@ -208,7 +175,42 @@ def test_current_phase_is_last_phase(self):
}
]

url = reverse("project-create", kwargs={"country_office_id": self.country_office.id})
url = reverse("project-create",
kwargs={"country_office_id": self.country_office.id})
response = self.test_user_client.post(url, data, format="json")
self.assertEqual(response.status_code, status.HTTP_201_CREATED, response.json())
self.assertEqual(response.json()['draft']['current_phase'], stages.last().id)
self.assertEqual(response.status_code,
status.HTTP_201_CREATED, response.json())
self.assertEqual(response.json()['draft']
['current_phase'], stages.last().id)


class StageTestCase(TestCase):
def setUp(self):
self.stage_data = {
'name': 'Test Stage',
# Set the value accordingly for your test
'completion_marks_an_initiative_as_inactive': True
}

def test_completion_marks_an_initiative_as_inactive(self):
# Create a stage
stage = Stage.objects.create(**self.stage_data)

# Retrieve the created stage from the database
created_stage = Stage.objects.get(id=stage.id)

# Assert the field value matches the expected value
self.assertEqual(created_stage.completion_marks_an_initiative_as_inactive,
self.stage_data['completion_marks_an_initiative_as_inactive'])

# Update the field value
new_value = False # Set the new value accordingly for your test
created_stage.completion_marks_an_initiative_as_inactive = new_value
created_stage.save()

# Retrieve the updated stage from the database
updated_stage = Stage.objects.get(id=stage.id)

# Assert the field value has been updated
self.assertEqual(
updated_stage.completion_marks_an_initiative_as_inactive, new_value)
Loading