Skip to content

Commit

Permalink
Merge pull request #1583 from akvo/#1447_iati_export_perf
Browse files Browse the repository at this point in the history
[#1447] IATI export performance
  • Loading branch information
kardan committed May 27, 2015
2 parents 1106d34 + a695516 commit 0c52d99
Show file tree
Hide file tree
Showing 17 changed files with 311 additions and 26 deletions.
10 changes: 7 additions & 3 deletions akvo/iati/checks/v201.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
'related_activity',
'legacy_data',
'conditions',
'results',
'crs_add',
'fss',
]
Expand Down Expand Up @@ -618,15 +619,18 @@ def results(self):

for result in self.project.results.all():
if not result.type:
checks.append((u'warning', u'result (id: %s) has no type '
self.all_checks_passed = False
checks.append((u'error', u'result (id: %s) has no type '
u'specified' % str(result.pk)))

if not result.title:
checks.append((u'warning', u'result (id: %s) has no title '
u'specified' % str(result.pk)))

if not result.indicators.all():
checks.append((u'warning', u'result (id: %s) has no indicators' % str(result.pk)))
if not result.indicators.all() and not result.description:
self.all_checks_passed = False
checks.append((u'error', u'result (id: %s) has no description and no '
u'indicator(s)' % str(result.pk)))

for indicator in result.indicators.all():
if not indicator.measure:
Expand Down
3 changes: 3 additions & 0 deletions akvo/rest/urls.py
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,9 @@
url(r'^user/(?P<pk>[0-9]+)/request_organisation/$',
views.request_organisation,
name='user_request_organisation'),
url(r'^project_iati_check/(?P<pk>[0-9]+)/$',
views.ProjectIatiCheckView.as_view(),
name='project_iati_check'),
)

# Typeahead
Expand Down
2 changes: 2 additions & 0 deletions akvo/rest/views/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,7 @@
from .project_document import ProjectDocumentViewSet
from .project_condition import ProjectConditionViewSet
from .project_contact import ProjectContactViewSet
from .project_iati_checks import ProjectIatiCheckView
from .project_location import ProjectLocationViewSet, MapProjectLocationViewSet
from .project_update import ProjectUpdateViewSet, ProjectUpdateExtraViewSet
from .project_update_location import ProjectUpdateLocationViewSet, MapProjectUpdateLocationViewSet
Expand Down Expand Up @@ -85,6 +86,7 @@
'ProjectContactViewSet',
'ProjectDocumentViewSet',
'ProjectExtraViewSet',
'ProjectIatiCheckView',
'ProjectLocationViewSet',
'ProjectUpdateExtraViewSet',
'ProjectUpdateLocationViewSet',
Expand Down
25 changes: 25 additions & 0 deletions akvo/rest/views/project_iati_checks.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
from akvo.rsr.models import Project
from django.http import Http404
from rest_framework.views import APIView
from rest_framework.response import Response


class ProjectIatiCheckView(APIView):
"""
List the result of IATI checks of a Project.
"""
def get_object(self, pk):
try:
return Project.objects.get(pk=pk)
except Project.DoesNotExist:
raise Http404

def get(self, request, pk, format=None):
project = self.get_object(pk)
check_results = project.check_mandatory_fields()
response = {
'all_checks_passed': str(check_results[0]),
'checks': check_results[1],
}

return Response(response)
16 changes: 1 addition & 15 deletions akvo/rsr/forms.py
Original file line number Diff line number Diff line change
Expand Up @@ -394,24 +394,10 @@ def __init__(self, user, *args, **kwargs):
)


class CustomLabelModelChoiceField(forms.ModelMultipleChoiceField):
def label_from_instance(self, obj):
checks = obj.check_mandatory_fields()
if checks[0]:
return mark_safe(u'<span class="success">%s</span>' % obj.__unicode__())
else:
label = obj.__unicode__()
for check in checks[1]:
if check[0] == u'error':
label += u'<br>- %s' % check[1]
return mark_safe(u'<span class="error">%s</span>' % label)



class IatiExportForm(forms.ModelForm):
"""Form for adding an entry to the IATI export model."""
is_public = forms.BooleanField(required=False, label=_(u"Show IATI file on organisation page"))
projects = CustomLabelModelChoiceField(
projects = forms.ModelMultipleChoiceField(
widget=forms.CheckboxSelectMultiple,
queryset=Project.objects.all(),
label=_(u"Select the projects included in the export:")
Expand Down
3 changes: 2 additions & 1 deletion akvo/rsr/static/scripts-src/my-details-employments.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ var AddEmploymentForm,
OrganisationInput,
ResponseModal,
initial_data,
request_link;
request_link,
i18n;



Expand Down
3 changes: 2 additions & 1 deletion akvo/rsr/static/scripts-src/my-details-employments.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ var AddEmploymentForm,
OrganisationInput,
ResponseModal,
initial_data,
request_link;
request_link,
i18n;



Expand Down
112 changes: 112 additions & 0 deletions akvo/rsr/static/scripts-src/my-iati.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/** @jsx React.DOM */

// Akvo RSR is covered by the GNU Affero General Public License.
// See more details in the license.txt file located at the root folder of the
// Akvo RSR module. For additional details on the GNU license please see
// < http://www.gnu.org/licenses/agpl.html >.

var i18n;

function loadAsync(url, retryCount, retryLimit, label) {
var xmlHttp;

xmlHttp = new XMLHttpRequest();

xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState == XMLHttpRequest.DONE) {

if(xmlHttp.status == 200){
processResponse(label, xmlHttp.responseText);
return true;
} else {
if (retryCount >= retryLimit) {
return false;
} else {
retryCount = retryCount + 1;
loadAsync(url, retryCount, retryLimit);
}
}
} else {
return false;
}
};

xmlHttp.open("GET", url, true);
xmlHttp.send();
}

function processResponse(label, response) {
var label_content, checks, all_checks_passed, span;

label_content = label.innerHTML;
checks = JSON.parse(response);

all_checks_passed = checks.all_checks_passed;

if (all_checks_passed === "True") {
span = document.createElement("span");
span.className = "success";
span.innerHTML = label_content;

label.innerHTML = '';
label.appendChild(span);

} else if (all_checks_passed === "False") {
span = document.createElement("span");
span.className = "error";
span.innerHTML = label_content;

label.innerHTML = '';
label.appendChild(span);
}
}

function getProjectLabels() {
var labels;

labels = document.getElementById('id_projects').getElementsByTagName('label');

for (var i = 0; i < labels.length; i++) {
var project_id;

project_id = labels[i].getElementsByTagName('input')[0].value;
loadAsync('/rest/v1/project_iati_check/' + project_id + '/?format=json', 0, 3, labels[i]);
}
}

function loadComponent(component_id) {
var Container;

Container = React.createClass({displayName: 'Container',
getInitialState: function() {
return {active_button: true};
},

handleClick: function() {
this.setState({active_button: false});
getProjectLabels();
},

render: function() {
if (this.state.active_button) {
return (
React.DOM.p(null,
React.DOM.button( {onClick:this.handleClick, className:"btn btn-primary"}, i18n.perform_checks)
)
);
} else {
return (
React.DOM.p(null)
);
}
}
});

React.render(
Container(null ),
document.getElementById(component_id)
);
}

i18n = JSON.parse(document.getElementById("perform-checks-text").innerHTML);
loadComponent('react_iati_checks');
112 changes: 112 additions & 0 deletions akvo/rsr/static/scripts-src/my-iati.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/** @jsx React.DOM */

// Akvo RSR is covered by the GNU Affero General Public License.
// See more details in the license.txt file located at the root folder of the
// Akvo RSR module. For additional details on the GNU license please see
// < http://www.gnu.org/licenses/agpl.html >.

var i18n;

function loadAsync(url, retryCount, retryLimit, label) {
var xmlHttp;

xmlHttp = new XMLHttpRequest();

xmlHttp.onreadystatechange = function() {
if (xmlHttp.readyState == XMLHttpRequest.DONE) {

if(xmlHttp.status == 200){
processResponse(label, xmlHttp.responseText);
return true;
} else {
if (retryCount >= retryLimit) {
return false;
} else {
retryCount = retryCount + 1;
loadAsync(url, retryCount, retryLimit);
}
}
} else {
return false;
}
};

xmlHttp.open("GET", url, true);
xmlHttp.send();
}

function processResponse(label, response) {
var label_content, checks, all_checks_passed, span;

label_content = label.innerHTML;
checks = JSON.parse(response);

all_checks_passed = checks.all_checks_passed;

if (all_checks_passed === "True") {
span = document.createElement("span");
span.className = "success";
span.innerHTML = label_content;

label.innerHTML = '';
label.appendChild(span);

} else if (all_checks_passed === "False") {
span = document.createElement("span");
span.className = "error";
span.innerHTML = label_content;

label.innerHTML = '';
label.appendChild(span);
}
}

function getProjectLabels() {
var labels;

labels = document.getElementById('id_projects').getElementsByTagName('label');

for (var i = 0; i < labels.length; i++) {
var project_id;

project_id = labels[i].getElementsByTagName('input')[0].value;
loadAsync('/rest/v1/project_iati_check/' + project_id + '/?format=json', 0, 3, labels[i]);
}
}

function loadComponent(component_id) {
var Container;

Container = React.createClass({
getInitialState: function() {
return {active_button: true};
},

handleClick: function() {
this.setState({active_button: false});
getProjectLabels();
},

render: function() {
if (this.state.active_button) {
return (
<p>
<button onClick={this.handleClick} className='btn btn-primary'>{i18n.perform_checks}</button>
</p>
);
} else {
return (
<p></p>
);
}
}
});

React.render(
<Container />,
document.getElementById(component_id)
);
}

i18n = JSON.parse(document.getElementById("perform-checks-text").innerHTML);
loadComponent('react_iati_checks');
3 changes: 2 additions & 1 deletion akvo/rsr/static/scripts-src/my-user-management.js
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ var ApproveModal,
Table = ReactBootstrap.Table,
TriggerModal,
UserTable,
initial_data;
initial_data,
i18n;


DeleteModal = React.createClass({displayName: 'DeleteModal',
Expand Down
3 changes: 2 additions & 1 deletion akvo/rsr/static/scripts-src/my-user-management.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@ var ApproveModal,
Table = ReactBootstrap.Table,
TriggerModal,
UserTable,
initial_data;
initial_data,
i18n;


DeleteModal = React.createClass({
Expand Down
1 change: 1 addition & 0 deletions akvo/rsr/static/scripts-src/password-reset.js
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ var Button = ReactBootstrap.Button;
var Modal = ReactBootstrap.Modal;
var ModalTrigger = ReactBootstrap.ModalTrigger;
var Input = ReactBootstrap.Input;
var i18n;

var ResetModal = React.createClass({displayName: 'ResetModal',
resetPassword: function() {
Expand Down
1 change: 1 addition & 0 deletions akvo/rsr/static/scripts-src/password-reset.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ var Button = ReactBootstrap.Button;
var Modal = ReactBootstrap.Modal;
var ModalTrigger = ReactBootstrap.ModalTrigger;
var Input = ReactBootstrap.Input;
var i18n;

var ResetModal = React.createClass({
resetPassword: function() {
Expand Down
3 changes: 2 additions & 1 deletion akvo/rsr/static/scripts-src/project-main.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@ var Accordion = ReactBootstrap.Accordion,
Carousel = ReactBootstrap.Carousel,
CarouselInstance,
CarouselItem = ReactBootstrap.CarouselItem,
Panel = ReactBootstrap.Panel;
Panel = ReactBootstrap.Panel,
i18n;

Indicator = React.createClass({displayName: 'Indicator',
render: function () {
Expand Down
Loading

0 comments on commit 0c52d99

Please sign in to comment.