Skip to content

Commit

Permalink
Merge pull request #800 from rdmorganiser/validate_conflicts
Browse files Browse the repository at this point in the history
Validate conflicts
  • Loading branch information
jochenklar committed Nov 16, 2023
2 parents 2f278c5 + e956649 commit d8dbae1
Show file tree
Hide file tree
Showing 21 changed files with 353 additions and 36 deletions.
19 changes: 19 additions & 0 deletions rdmo/core/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -58,3 +58,22 @@
'views.add_view', 'views.change_view', 'views.delete_view'
)
}

HUMAN2BYTES_MAPPER = {
"b": {"base": 1000, "power": 0},
"kb": {"base": 1000, "power": 1},
"k": {"base": 1000, "power": 1},
"mb": {"base": 1000, "power": 2},
"m": {"base": 1000, "power": 2},
"gb": {"base": 1000, "power": 3},
"g": {"base": 1000, "power": 3},
"tb": {"base": 1000, "power": 4},
"t": {"base": 1000, "power": 4},
"p": {"base": 1000, "power": 5},
"pb": {"base": 1000, "power": 5},
"kib": {"base": 1024, "power": 1},
"mib": {"base": 1024, "power": 2},
"gib": {"base": 1024, "power": 3},
"tib": {"base": 1024, "power": 4},
"pib": {"base": 1024, "power": 5},
}
15 changes: 14 additions & 1 deletion rdmo/core/tests/test_utils.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
from typing import Optional

import pytest

from rdmo.core.utils import join_url, sanitize_url
from rdmo.core.utils import human2bytes, join_url, sanitize_url

urls = (
('', ''),
Expand All @@ -15,6 +17,12 @@
(1, ''),
)

human2bytes_test_values = (
("1Gb", 1e+9),
(None, 0),
("0", 0),
)


@pytest.mark.parametrize("url,sanitized_url", urls)
def test_sanitize_url(url, sanitized_url):
Expand All @@ -23,3 +31,8 @@ def test_sanitize_url(url, sanitized_url):

def test_join_url():
assert join_url('https://example.com//', '/terms', 'foo') == 'https://example.com/terms/foo'


@pytest.mark.parametrize("human,bytes", human2bytes_test_values)
def test_human2bytes(human: Optional[str], bytes: float):
assert human2bytes(human) == bytes
27 changes: 6 additions & 21 deletions rdmo/core/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
from defusedcsv import csv
from markdown import markdown

from .constants import HUMAN2BYTES_MAPPER

log = logging.getLogger(__name__)


Expand Down Expand Up @@ -351,32 +353,15 @@ def copy_model(instance, **kwargs):


def human2bytes(string):
if not string:
if not string or string == '0':
return 0

m = re.match(r'([0-9.]+)\s*([A-Za-z]+)', string)
number, unit = float(m.group(1)), m.group(2).strip().lower()

if unit == 'kb' or unit == 'k':
return number * 1000
elif unit == 'mb' or unit == 'm':
return number * 1000**2
elif unit == 'gb' or unit == 'g':
return number * 1000**3
elif unit == 'tb' or unit == 't':
return number * 1000**4
elif unit == 'pb' or unit == 'p':
return number * 1000**5
elif unit == 'kib':
return number * 1024
elif unit == 'mib':
return number * 1024**2
elif unit == 'gib':
return number * 1024**3
elif unit == 'tib':
return number * 1024**4
elif unit == 'pib':
return number * 1024**5
conversion = HUMAN2BYTES_MAPPER[unit]
number = number*conversion['base']**(conversion['power'])
return number


def is_truthy(value):
Expand Down
7 changes: 5 additions & 2 deletions rdmo/projects/serializers/v1/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from rdmo.services.validators import ProviderValidator

from ...models import Integration, IntegrationOption, Invite, Issue, IssueResource, Membership, Project, Snapshot, Value
from ...validators import ValueValidator
from ...validators import ValueConflictValidator, ValueQuotaValidator


class UserSerializer(serializers.ModelSerializer):
Expand Down Expand Up @@ -259,7 +259,10 @@ class Meta:
'unit',
'external_id'
)
validators = (ValueValidator(), )
validators = (
ValueConflictValidator(),
ValueQuotaValidator()
)


class MembershipSerializer(serializers.ModelSerializer):
Expand Down
19 changes: 18 additions & 1 deletion rdmo/projects/static/projects/js/project_questions/services.js
Original file line number Diff line number Diff line change
Expand Up @@ -706,6 +706,9 @@ angular.module('project_questions')
};

service.storeValue = function(value, question, set_prefix, set_index, collection_index) {
// reset value errors
value.errors = []

if (angular.isDefined(value.removed) && value.removed) {
// remove additional_input from unselected checkboxes
value.additional_input = {};
Expand Down Expand Up @@ -826,10 +829,16 @@ angular.module('project_questions')
}, function (response) {
if (response.status == 500) {
service.error = response;
} else if (response.status == 400) {
service.error = true;
value.errors = Object.keys(response.data);
} else if (response.status == 404) {
service.error = true;
value.errors = ['not_found']
}
})
}
};
};

service.storeValues = function() {
var promises = [];
Expand Down Expand Up @@ -1058,11 +1067,19 @@ angular.module('project_questions')
service.values[attribute][set_prefix][set_index][collection_index].autocomplete_text = '';
service.values[attribute][set_prefix][set_index][collection_index].autocomplete_locked = false;
service.values[attribute][set_prefix][set_index][collection_index].changed = true;

if (service.settings.project_questions_autosave) {
service.save(false);
}
};

service.removeValue = function(attribute, set_prefix, set_index, collection_index) {
service.values[attribute][set_prefix][set_index][collection_index].removed = true;
service.values[attribute][set_prefix][set_index][collection_index].changed = true;

if (service.settings.project_questions_autosave) {
service.save(false);
}
};

service.openValueSetFormModal = function(questionset, set_prefix, set_index) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,8 @@
</div>
</div>
</div>

{% include 'projects/project_questions_value_errors.html' %}
</div>

<div ng-if="question.is_collection">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,9 @@
ng-disabled="service.project.read_only"
ng-change="service.changed(service.values[question.attribute][valueset.set_prefix][valueset.set_index][$index])" />
</label>
<div ng-init="value = service.values[question.attribute][valueset.set_prefix][valueset.set_index][$index]">
{% include 'projects/project_questions_value_errors.html' %}
</div>
</div>
</div>
</div>
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@
ng-change="service.changed(value, true)"
ng-class="{'default-value': service.isDefaultValue(question, value)}"/>
</div>

{% include 'projects/project_questions_value_errors.html' %}
</div>

<div ng-if="question.is_collection">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@
</ul>
</label>
</div>

{% include 'projects/project_questions_value_errors.html' %}
</div>

<div ng-if="question.is_collection">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@
</div>
</div>
</div>

{% include 'projects/project_questions_value_errors.html' %}
</div>

<div ng-if="question.is_collection">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,8 @@
ng-class="{'default-value': service.isDefaultValue(question, value)}"/>
</div>
</div>

{% include 'projects/project_questions_value_errors.html' %}
</div>

<div ng-if="question.is_collection">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,8 @@
</option>
</select>
</div>

{% include 'projects/project_questions_value_errors.html' %}
</div>

<div ng-if="question.is_collection">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@
ng-disabled="service.project.read_only"
ng-change="service.changed(value)"
ng-class="{'default-value': service.isDefaultValue(question, value)}">

{% include 'projects/project_questions_value_errors.html' %}
</div>
</div>

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
ng-class="{'default-value': service.isDefaultValue(question, value)}">
</textarea>
</div>

{% include 'projects/project_questions_value_errors.html' %}
</div>

<div ng-if="question.is_collection">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@
</div>
</div>
</div>

{% include 'projects/project_questions_value_errors.html' %}
</div>

<div ng-if="question.is_collection">
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,9 @@
</ul>

<ul class="list-unstyled">
<li>
<a href="#" onclick="window.location.reload();">{% trans 'Reload page' %}</a>
</li>
<li>
<a href="{% url 'projects' %}">{% trans 'Back to my projects' %}</a>
</li>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{% load i18n %}
{% load core_tags %}

<div class="text-danger" ng-show="service.error">
<div class="text-danger" ng-show="service.error.statusText && service.error.status">
<p>
{% trans 'An error occurred while saving the answer. Please contact support if this problem persists.' %}
</p>
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
{% load i18n %}

<ul class="help-block list-unstyled" ng-if="value.errors.length > 0">
<li class="text-danger" ng-repeat="error in value.errors">
<span ng-show="error == 'conflict'">
{% blocktrans trimmed %}
This field could not be saved, since somebody else did so while you were editing.
You will need to reload the page to make changes, but your input will be overwritten.
{% endblocktrans %}
</span>
<span ng-show="error == 'not_found'">
{% blocktrans trimmed %}
This field could not be saved, since somebody else removed it while you were editing.
You will need to reload the page to proceed, but your input will be lost.
{% endblocktrans %}
</span>
<span ng-show="error == 'quota'">
{% trans 'You reached the file quota for this project.' %}
</span>
</li>
</ul>
Loading

0 comments on commit d8dbae1

Please sign in to comment.