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

Develop #1760

Merged
merged 35 commits into from
Jul 20, 2022
Merged

Develop #1760

Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
35 commits
Select commit Hold shift + click to select a range
5544bb6
[ch28580] PRP: xls export incorrect values
emaciupe Mar 2, 2022
c49ad58
[ch28750] Added a 404 & 500 html page
emaciupe Mar 17, 2022
4b6d44c
[ch28772][sentry-6395] Fix pdf export of progress report
emaciupe Mar 18, 2022
b6e5836
Merge branch 'develop' of github.com:unicef/etools-partner-reporting-…
emaciupe Mar 28, 2022
adbd9e9
Code review changes: replace GA with Matomo js
emaciupe Mar 28, 2022
247a6a2
Added JSONSchemaValidator based on jsonschema lib for indicator json …
emaciupe Apr 18, 2022
2432d4e
flake8
emaciupe Apr 19, 2022
1a477f9
Merge branch 'develop' of github.com:unicef/etools-partner-reporting-…
emaciupe Apr 26, 2022
dac31a0
Code review: add user id for matomo tracking
emaciupe Apr 26, 2022
4ed1601
[ch17503] Update matomo tracker (#1747)
danNordlogic Apr 26, 2022
fe5f4cf
[ch29269] QPR/SR: Loading not going away after Other 3 attachment upl…
danNordlogic Apr 27, 2022
da6a258
Merge branch 'staging' into develop
robertavram Jun 1, 2022
d8aa538
docker-compose update for db
robertavram Jun 6, 2022
30a1b17
[ch30133]Fix empty locations dropdown (#1761)
acory Jun 7, 2022
fee79e5
[ch30131] Black background when entering data on indicators (#1765)
danNordlogic Jun 7, 2022
b9ca18d
[ch30147] Search by input is not updated properly (#1766)
danNordlogic Jun 7, 2022
57650ee
[ch30251] Fix app in Edge, Firefox (#1768)
acory Jun 14, 2022
0748909
[ch30438][ar lang]Fix profile dropdown overlap (#1771)
acory Jun 30, 2022
8342fc4
[ch30008] Replace deprecated 'substr' method (#1769)
acory Jun 30, 2022
d286c13
submodule ref (#1772)
acory Jun 30, 2022
11ecea1
[ch30530] Update logout url to `/social/unicef-logout/` (#1773)
danNordlogic Jul 4, 2022
184158d
[ch30530] Update logout url to /social/unicef-logout/ (#1774)
danNordlogic Jul 4, 2022
7aef7c6
[ch30515] Calculation Methods label for Ratio Indicator is 'latest' i…
danNordlogic Jul 12, 2022
76dcd57
submodule ref
acory Jul 12, 2022
9949881
submodule ref
acory Jul 12, 2022
9d0b34d
Submodule ref (#1777)
acory Jul 14, 2022
10abc9a
Merge branch 'develop' into 28580-xls-export-incorrect-values
robertavram Jul 18, 2022
f451570
Merge pull request #1701 from unicef/28580-xls-export-incorrect-values
robertavram Jul 18, 2022
b52a132
Merge branch 'develop' into 28772-export-decimal-error
robertavram Jul 18, 2022
051dff5
Merge pull request #1717 from unicef/28772-export-decimal-error
robertavram Jul 18, 2022
2ae52ec
Merge branch 'develop' into 29016-indicator-data-validator
robertavram Jul 18, 2022
29efbf3
Merge pull request #1744 from unicef/29016-indicator-data-validator
robertavram Jul 18, 2022
def609f
Merge branch 'develop' into 28750-add-404-page
robertavram Jul 18, 2022
0d7dd95
Merge pull request #1716 from unicef/28750-add-404-page
robertavram Jul 18, 2022
eb1dd93
[ch30530] Update logout url to /social/unicef-logout/ (#1784)
danNordlogic Jul 20, 2022
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
2 changes: 2 additions & 0 deletions .circleci/config.yml
Original file line number Diff line number Diff line change
Expand Up @@ -255,6 +255,8 @@ workflows:
- master
- staging
- develop
- submodule-ref-2

- build_and_deploy_fe_cluster:
filters:
branches:
Expand Down
2 changes: 1 addition & 1 deletion db/Dockerfile
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ FROM postgis/postgis:12-3.1
RUN apt-get update && apt-get install -y --no-install-recommends bzip2

# Use this if there is a db dump file
COPY ./db1.bz2 /tmp/psql_data/

COPY load_db_data.sh /docker-entrypoint-initdb.d/20_load_db_data.sh

EXPOSE 5432
Expand Down
6 changes: 3 additions & 3 deletions db/load_db_data.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

set -e

export DB_DUMP_LOCATION=/tmp/psql_data/db1.bz2
export DB_DUMP_LOCATION=/tmp/psql_data/db_dump.bz2

echo "*** RESTORING DATABASE $POSTGRES_DB ***"
bzcat $DB_DUMP_LOCATION | nice pg_restore --verbose -U $POSTGRES_USER -F t -d $POSTGRES_DB
# bzcat $DB_DUMP_LOCATION | nice pg_restore --verbose -U $POSTGRES_USER -F c -d $POSTGRES_DB
#bzcat $DB_DUMP_LOCATION | nice pg_restore --verbose -U $POSTGRES_USER -F t -d $POSTGRES_DB
bzcat $DB_DUMP_LOCATION | nice pg_restore --verbose -U $POSTGRES_USER -F c -d $POSTGRES_DB

echo "*** DATABASE CREATED ***"
7 changes: 4 additions & 3 deletions django_api/Dockerfile-base
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
FROM python:3.9.6-alpine3.14

RUN apk update

RUN apk add \
--update alpine-sdk

RUN apk add --upgrade apk-tools \
openssl \
ca-certificates \
Expand All @@ -26,9 +30,6 @@ RUN apk add --no-cache --virtual .build-deps --update \
gcc \
g++


# PYTHON
RUN pip install --no-cache-dir --upgrade \
setuptools \
pip \
pipenv
1 change: 1 addition & 0 deletions django_api/Pipfile
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,7 @@ djangorestframework-gis = "<=0.17"
djangorestframework-simplejwt = "<=4.8"
drfpasswordless = "<=1.5.7"
greenlet = "<=1.1.1"
jsonschema = "<=4.4.0"
newrelic = "<=6.8.0.163"
openpyxl = "<=3.0.7"
psycopg2-binary = "<=2.9.1"
Expand Down
37 changes: 36 additions & 1 deletion django_api/Pipfile.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Empty file.
13 changes: 13 additions & 0 deletions django_api/etools_prp/apps/core/templatetags/prp.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
from django import template
from django.conf import settings
from django.utils.safestring import mark_safe

register = template.Library()


@register.simple_tag
def matomo_settings(name):
_settings = ("MATOMO_HOST_URL", "MATOMO_TRACKER_URL", "MATOMO_SITE_ID")
if name in _settings:
return mark_safe(getattr(settings, name, ''))
return ''
32 changes: 29 additions & 3 deletions django_api/etools_prp/apps/core/validators.py
Original file line number Diff line number Diff line change
@@ -1,14 +1,17 @@
from django.contrib.contenttypes.models import ContentType
from django.core import exceptions
from django.utils.deconstruct import deconstructible
from django.utils.translation import gettext_lazy as _

from jsonschema import exceptions as jsonschema_exceptions, validate
from rest_framework.exceptions import ValidationError

from etools_prp.apps.cluster.models import ClusterActivity, ClusterObjective
from etools_prp.apps.partner.models import PartnerActivity, PartnerActivityProjectContext, PartnerProject


class AddIndicatorObjectTypeValidator:

def __call__(self, value):
from etools_prp.apps.cluster.models import ClusterActivity, ClusterObjective
from etools_prp.apps.partner.models import PartnerActivity, PartnerActivityProjectContext, PartnerProject
model_choices = {
ClusterObjective,
ClusterActivity,
Expand All @@ -26,3 +29,26 @@ def __call__(self, value):


add_indicator_object_type_validator = AddIndicatorObjectTypeValidator()


@deconstructible
class JSONSchemaValidator:
message = _("Invalid JSON: %(value)s")
code = 'invalid_json'

def __init__(self, json_schema, message=None):
self.json_schema = json_schema
if message:
self.message = message

def __call__(self, value):
try:
validate(value, self.json_schema)
except jsonschema_exceptions.ValidationError as e:
raise exceptions.ValidationError(self.message, code=self.code, params={'value': e.message})

def __eq__(self, other):
return isinstance(other, self.__class__) and \
self.json_schema == other.json_schema and \
self.message == other.message and \
self.code == other.code
22 changes: 22 additions & 0 deletions django_api/etools_prp/apps/indicator/json_schemas.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@


indicator_schema = {
"title": "Json schema for total, target, baseline and in_need fields",
"type": "object",
"additionalProperties": False,
"properties": {
"c": {"type": "number"},
"d": {"type": "number"},
"v": {"type": "number"}
},
"required": ["d", "v"]
}

disaggregation_schema = {
"title": "Disaggregation json schema",
"type": "object",
"additionalProperties": False,
"patternProperties": {
"^\((\d*,\s*)*\d*\)$": indicator_schema # noqa W605
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
# Generated by Django 3.2.6 on 2022-04-18 17:14

from django.db import migrations, models
import etools_prp.apps.core.validators
import etools_prp.apps.indicator.models


class Migration(migrations.Migration):

dependencies = [
('indicator', '0008_alter_indicatorlocationdata_disaggregation'),
]

operations = [
migrations.AlterField(
model_name='indicatorlocationdata',
name='disaggregation',
field=models.JSONField(default=etools_prp.apps.indicator.models.default_disaggregation, validators=[etools_prp.apps.core.validators.JSONSchemaValidator(json_schema={'additionalProperties': False, 'patternProperties': {'^\\((\\d*,\\s*)*\\d*\\)$': {'additionalProperties': False, 'properties': {'c': {'type': 'number'}, 'd': {'type': 'number'}, 'v': {'type': 'number'}}, 'required': ['d', 'v'], 'title': 'Json schema for total, target, baseline and in_need fields', 'type': 'object'}}, 'title': 'Disaggregation json schema', 'type': 'object'})]),
),
migrations.AlterField(
model_name='indicatorreport',
name='total',
field=models.JSONField(default=etools_prp.apps.indicator.models.default_total, validators=[etools_prp.apps.core.validators.JSONSchemaValidator(json_schema={'additionalProperties': False, 'properties': {'c': {'type': 'number'}, 'd': {'type': 'number'}, 'v': {'type': 'number'}}, 'required': ['d', 'v'], 'title': 'Json schema for total, target, baseline and in_need fields', 'type': 'object'})]),
),
migrations.AlterField(
model_name='reportable',
name='baseline',
field=models.JSONField(default=etools_prp.apps.indicator.models.default_value, validators=[etools_prp.apps.core.validators.JSONSchemaValidator(json_schema={'additionalProperties': False, 'properties': {'c': {'type': 'number'}, 'd': {'type': 'number'}, 'v': {'type': 'number'}}, 'required': ['d', 'v'], 'title': 'Json schema for total, target, baseline and in_need fields', 'type': 'object'})]),
),
migrations.AlterField(
model_name='reportable',
name='in_need',
field=models.JSONField(blank=True, null=True, validators=[etools_prp.apps.core.validators.JSONSchemaValidator(json_schema={'additionalProperties': False, 'properties': {'c': {'type': 'number'}, 'd': {'type': 'number'}, 'v': {'type': 'number'}}, 'required': ['d', 'v'], 'title': 'Json schema for total, target, baseline and in_need fields', 'type': 'object'})]),
),
migrations.AlterField(
model_name='reportable',
name='target',
field=models.JSONField(default=etools_prp.apps.indicator.models.default_value, validators=[etools_prp.apps.core.validators.JSONSchemaValidator(json_schema={'additionalProperties': False, 'properties': {'c': {'type': 'number'}, 'd': {'type': 'number'}, 'v': {'type': 'number'}}, 'required': ['d', 'v'], 'title': 'Json schema for total, target, baseline and in_need fields', 'type': 'object'})]),
),
migrations.AlterField(
model_name='reportable',
name='total',
field=models.JSONField(default=etools_prp.apps.indicator.models.default_total, validators=[etools_prp.apps.core.validators.JSONSchemaValidator(json_schema={'additionalProperties': False, 'properties': {'c': {'type': 'number'}, 'd': {'type': 'number'}, 'v': {'type': 'number'}}, 'required': ['d', 'v'], 'title': 'Json schema for total, target, baseline and in_need fields', 'type': 'object'})]),
),
migrations.AlterField(
model_name='reportablelocationgoal',
name='baseline',
field=models.JSONField(default=etools_prp.apps.indicator.models.default_value, validators=[etools_prp.apps.core.validators.JSONSchemaValidator(json_schema={'additionalProperties': False, 'properties': {'c': {'type': 'number'}, 'd': {'type': 'number'}, 'v': {'type': 'number'}}, 'required': ['d', 'v'], 'title': 'Json schema for total, target, baseline and in_need fields', 'type': 'object'})]),
),
migrations.AlterField(
model_name='reportablelocationgoal',
name='in_need',
field=models.JSONField(blank=True, null=True, validators=[etools_prp.apps.core.validators.JSONSchemaValidator(json_schema={'additionalProperties': False, 'properties': {'c': {'type': 'number'}, 'd': {'type': 'number'}, 'v': {'type': 'number'}}, 'required': ['d', 'v'], 'title': 'Json schema for total, target, baseline and in_need fields', 'type': 'object'})]),
),
migrations.AlterField(
model_name='reportablelocationgoal',
name='target',
field=models.JSONField(default=etools_prp.apps.indicator.models.default_value, validators=[etools_prp.apps.core.validators.JSONSchemaValidator(json_schema={'additionalProperties': False, 'properties': {'c': {'type': 'number'}, 'd': {'type': 'number'}, 'v': {'type': 'number'}}, 'required': ['d', 'v'], 'title': 'Json schema for total, target, baseline and in_need fields', 'type': 'object'})]),
),
]
44 changes: 35 additions & 9 deletions django_api/etools_prp/apps/indicator/models.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,10 @@
REPORTING_TYPES,
)
from etools_prp.apps.core.models import TimeStampedExternalSourceModel
from etools_prp.apps.core.validators import JSONSchemaValidator
from etools_prp.apps.indicator.constants import ValueType
from etools_prp.apps.indicator.disaggregators import QuantityIndicatorDisaggregator, RatioIndicatorDisaggregator
from etools_prp.apps.indicator.json_schemas import disaggregation_schema, indicator_schema
from etools_prp.apps.indicator.utilities import convert_string_number_to_float
from etools_prp.apps.partner.models import PartnerActivity
from etools_prp.apps.utils.emails import send_email_from_template
Expand Down Expand Up @@ -241,9 +243,18 @@ class Reportable(TimeStampedExternalSourceModel):
cluster.ClusterObjective (ForeignKey): "content_object"
self (ForeignKey): "parent_indicator"
"""
target = models.JSONField(default=default_value)
baseline = models.JSONField(default=default_value)
in_need = models.JSONField(blank=True, null=True)
target = models.JSONField(
default=default_value,
validators=[JSONSchemaValidator(json_schema=indicator_schema)]
)
baseline = models.JSONField(
default=default_value,
validators=[JSONSchemaValidator(json_schema=indicator_schema)]
)
in_need = models.JSONField(
blank=True, null=True,
validators=[JSONSchemaValidator(json_schema=indicator_schema)]
)
assumptions = models.TextField(null=True, blank=True)
means_of_verification = models.CharField(max_length=255, null=True, blank=True)
comments = models.TextField(max_length=4048, blank=True, null=True)
Expand All @@ -260,7 +271,7 @@ class Reportable(TimeStampedExternalSourceModel):

# Current total, transactional and dynamically calculated based on
# IndicatorReports
total = models.JSONField(default=default_total)
total = models.JSONField(default=default_total, validators=[JSONSchemaValidator(json_schema=indicator_schema)])

# unique code for this indicator within the current context
# eg: (1.1) result code 1 - indicator code 1
Expand Down Expand Up @@ -633,9 +644,18 @@ def clone_ca_reportable_to_pa_signal(sender, instance, created, **kwargs):
class ReportableLocationGoal(TimeStampedModel):
reportable = models.ForeignKey(Reportable, on_delete=models.CASCADE)
location = models.ForeignKey("core.Location", on_delete=models.CASCADE)
target = models.JSONField(default=default_value)
baseline = models.JSONField(default=default_value)
in_need = models.JSONField(blank=True, null=True)
target = models.JSONField(
default=default_value,
validators=[JSONSchemaValidator(json_schema=indicator_schema)]
)
baseline = models.JSONField(
default=default_value,
validators=[JSONSchemaValidator(json_schema=indicator_schema)]
)
in_need = models.JSONField(
blank=True, null=True,
validators=[JSONSchemaValidator(json_schema=indicator_schema)]
)
is_active = models.BooleanField(default=True)

class Meta:
Expand Down Expand Up @@ -685,7 +705,10 @@ class IndicatorReport(TimeStampedModel):
verbose_name='Frequency of reporting'
)

total = models.JSONField(default=default_total)
total = models.JSONField(
default=default_total,
validators=[JSONSchemaValidator(json_schema=indicator_schema)]
)

remarks = models.TextField(blank=True, null=True)
report_status = models.CharField(
Expand Down Expand Up @@ -1068,7 +1091,10 @@ class IndicatorLocationData(TimeStampedModel):
on_delete=models.CASCADE,
)

disaggregation = models.JSONField(default=default_disaggregation)
disaggregation = models.JSONField(
default=default_disaggregation,
validators=[JSONSchemaValidator(json_schema=disaggregation_schema)]
)
num_disaggregation = models.IntegerField()
level_reported = models.IntegerField()
disaggregation_reported_on = ArrayField(models.IntegerField(), default=list)
Expand Down
Loading