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

SPT-6352: First created and last updated (user and date stamp) should throw error when user tries to set value #170

Draft
wants to merge 11 commits into
base: master
Choose a base branch
from
30 changes: 13 additions & 17 deletions functional_tests/driver_tests/test_date_time_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -166,22 +166,20 @@ def test_first_created_field_value(helpers):
**{"Required Date & Time": pendulum.now()})
assert theRecord["First Created"] != None

@pytest.mark.xfail(reason="SPT-6352: The First created should have been blocked from being set.")
def test_first_created_field(helpers):
datetimeValue = pendulum.tomorrow()
theRecord = pytest.app.records.create(
with pytest.raises(ValueError) as excinfo:
pytest.app.records.create(
**{"Required Date & Time": pendulum.now(), "First Created": datetimeValue})
assert theRecord["First Created"] != datetimeValue
assert str(excinfo.value) == 'Input type "firstCreated" is not editable'

@pytest.mark.xfail(reason="SPT-6352: The First created should have been blocked from being set.")
def test_first_created_field_on_save(helpers):
datetimeValue = pendulum.tomorrow()
theRecord = pytest.app.records.create(
**{"Required Date & Time": pendulum.now()})
theOriginalTimeCreated = theRecord["First Created"]
theRecord["First Created"] = datetimeValue
theRecord.save()
assert theRecord["First Created"] == theOriginalTimeCreated
with pytest.raises(ValueError) as excinfo:
theRecord["First Created"] = datetimeValue
assert str(excinfo.value) == 'Input type "firstCreated" is not editable'


class TestLastUpdatedField:
Expand All @@ -190,22 +188,20 @@ def test_last_updated_field_value(helpers):
**{"Required Date & Time": pendulum.now()})
assert theRecord["Last Updated"] >= theRecord["First Created"]

@pytest.mark.xfail(reason="SPT-6352: The Last updated should have been blocked from being set.")
def test_last_updated_field(helpers):
datetimeValue = pendulum.yesterday()
theRecord = pytest.app.records.create(
**{"Required Date & Time": pendulum.now(), "Last Updated": datetimeValue})
assert theRecord["Last Updated"] != datetimeValue
with pytest.raises(ValueError) as excinfo:
pytest.app.records.create(
**{"Required Date & Time": pendulum.now(), "Last Updated": datetimeValue})
assert str(excinfo.value) == 'Input type "lastUpdated" is not editable'

@pytest.mark.xfail(reason="SPT-6352: The Last updated should have been blocked from being set.")
def test_last_updated_field_on_save(helpers):
datetimeValue = pendulum.yesterday()
theRecord = pytest.app.records.create(
**{"Required Date & Time": pendulum.now()})
theRecord["Last Updated"] = datetimeValue
theRecord.save()
assert theRecord["First Created"] < theRecord["Last Updated"]
assert theRecord["Last Updated"] != datetimeValue
with pytest.raises(ValueError) as excinfo:
theRecord["Last Updated"] = datetimeValue
assert str(excinfo.value) == 'Input type "lastUpdated" is not editable'


class TestTimespanField:
Expand Down
48 changes: 20 additions & 28 deletions functional_tests/driver_tests/test_records_bulk_adaptor.py
Original file line number Diff line number Diff line change
Expand Up @@ -396,49 +396,41 @@ def test_record_bulk_modify_clear_first_created(helpers):
baseTime = pendulum.now()
pytest.app.records.bulk_create({'Date & Time': baseTime}, {'Date & Time': baseTime}, {
'Date & Time': baseTime}, {'Date & Time': baseTime})
emptyNumericRecords = len(pytest.app.records.search(
('First Created', 'equals', None)))
records = pytest.app.records.bulk_modify(
('Date & Time', 'equals', baseTime), values={'First Created': Clear()})
pytest.waitOnJobByID(records)
assert len(pytest.app.records.search(
('First Created', 'equals', None))) == emptyNumericRecords
with pytest.raises(ValueError) as excinfo:
records = pytest.app.records.bulk_modify(
('Date & Time', 'equals', baseTime), values={'First Created': Clear()})
pytest.waitOnJobByID(records)
assert str(excinfo.value) == 'Input type "firstCreated" is not editable'

def test_record_bulk_modify_clear_last_updated(helpers):
baseTime = pendulum.now()
pytest.app.records.bulk_create({'Date & Time': baseTime}, {'Date & Time': baseTime}, {
'Date & Time': baseTime}, {'Date & Time': baseTime})
emptyNumericRecords = len(pytest.app.records.search(
('Last Updated', 'equals', None)))
records = pytest.app.records.bulk_modify(
('Date & Time', 'equals', baseTime), values={'Last Updated': Clear()})
pytest.waitOnJobByID(records)
assert len(pytest.app.records.search(
('Last Updated', 'equals', None))) == emptyNumericRecords
with pytest.raises(ValueError) as excinfo:
records = pytest.app.records.bulk_modify(
('Date & Time', 'equals', baseTime), values={'Last Updated': Clear()})
pytest.waitOnJobByID(records)
assert str(excinfo.value) == 'Input type "lastUpdated" is not editable'

def test_record_bulk_modify_clear_created_by(helpers):
baseTime = pendulum.now()
pytest.app.records.bulk_create({'Date & Time': baseTime}, {'Date & Time': baseTime}, {
'Date & Time': baseTime}, {'Date & Time': baseTime})
emptyNumericRecords = len(
pytest.app.records.search(('Created by', 'equals', None)))
records = pytest.app.records.bulk_modify(
('Date & Time', 'equals', baseTime), values={'Created by': Clear()})
pytest.waitOnJobByID(records)
assert len(pytest.app.records.search(
('Created by', 'equals', None))) == emptyNumericRecords
with pytest.raises(ValueError) as excinfo:
records = pytest.app.records.bulk_modify(
('Date & Time', 'equals', baseTime), values={'Created by': Clear()})
pytest.waitOnJobByID(records)
assert str(excinfo.value) == 'Input type "createdBy" is not editable'

def test_record_bulk_modify_clear_last_updated_by(helpers):
baseTime = pendulum.now()
pytest.app.records.bulk_create({'Date & Time': baseTime}, {'Date & Time': baseTime}, {
'Date & Time': baseTime}, {'Date & Time': baseTime})
emptyNumericRecords = len(pytest.app.records.search(
('Last updated by', 'equals', None)))
records = pytest.app.records.bulk_modify(
('Date & Time', 'equals', baseTime), values={'Last updated by': Clear()})
pytest.waitOnJobByID(records)
assert len(pytest.app.records.search(
('Last updated by', 'equals', None))) == emptyNumericRecords
with pytest.raises(ValueError) as excinfo:
records = pytest.app.records.bulk_modify(
('Date & Time', 'equals', baseTime), values={'Last updated by': Clear()})
pytest.waitOnJobByID(records)
assert str(excinfo.value) == 'Input type "lastUpdatedBy" is not editable'

def test_record_bulk_modify_clear_attachment(helpers):
baseText = "Has Attachment"
Expand Down
31 changes: 15 additions & 16 deletions functional_tests/driver_tests/test_user_group_fields.py
Original file line number Diff line number Diff line change
Expand Up @@ -144,25 +144,24 @@ def test_created_by_field_value(helpers):
**{"Required User/Groups": swimUser})
assert theRecord["Created by"] == swimUser

@pytest.mark.xfail(reason="SPT-6352: This should fail, that the Created by is read only.")
def test_created_by_field(helpers):
swimUser = pytest.swimlane_instance.users.get(display_name="admin")
swimUser2 = pytest.swimlane_instance.users.get(
display_name=pytest.testUsers[pytest.fake.random_int(0, len(pytest.testUsers)-1)])
theRecord = pytest.app.records.create(
**{"Required User/Groups": swimUser, "Created by": swimUser2})
assert theRecord["Created by"] == swimUser
with pytest.raises(ValueError) as excinfo:
pytest.app.records.create(
**{"Required User/Groups": swimUser, "Created by": swimUser2})
assert str(excinfo.value) == 'Input type "createdBy" is not editable'

@pytest.mark.xfail(reason="SPT-6352: This should fail, that the Created by is read only.")
def test_created_by_field_on_save(helpers):
swimUser = pytest.swimlane_instance.users.get(display_name="admin")
swimUser2 = pytest.swimlane_instance.users.get(
display_name=pytest.testUsers[pytest.fake.random_int(0, len(pytest.testUsers)-1)])
theRecord = pytest.app.records.create(
**{"Required User/Groups": swimUser})
theRecord["Created by"] = swimUser2
theRecord.save()
assert theRecord["Created by"] == swimUser
with pytest.raises(ValueError) as excinfo:
theRecord["Created by"] = swimUser2
assert str(excinfo.value) == 'Input type "createdBy" is not editable'


class TestLastUpdatedByField:
Expand All @@ -172,25 +171,25 @@ def test_last_updated_by_field_value(helpers):
**{"Required User/Groups": swimUser})
assert theRecord["Last updated by"] == swimUser

@pytest.mark.xfail(reason="SPT-6352: This should fail, that the last updated by is read only.")
def test_last_updated_by_field(helpers):
swimUser = pytest.swimlane_instance.users.get(display_name="admin")
swimUser2 = pytest.swimlane_instance.users.get(
display_name=pytest.testUsers[pytest.fake.random_int(0, len(pytest.testUsers)-1)])
theRecord = pytest.app.records.create(
**{"Required User/Groups": swimUser, "Last updated by": swimUser2})
assert theRecord["Last updated by"] == swimUser
with pytest.raises(ValueError) as excinfo:
pytest.app.records.create(
**{"Required User/Groups": swimUser, "Last updated by": swimUser2})
assert str(excinfo.value) == 'Input type "lastUpdatedBy" is not editable'


@pytest.mark.xfail(reason="SPT-6352: This should fail, that the Last updated by is read only.")
def test_last_updated_by_field_on_save(helpers):
swimUser = pytest.swimlane_instance.users.get(display_name="admin")
swimUser2 = pytest.swimlane_instance.users.get(
display_name=pytest.testUsers[pytest.fake.random_int(0, len(pytest.testUsers)-1)])
theRecord = pytest.app.records.create(
**{"Required User/Groups": swimUser})
theRecord["Last updated by"] = swimUser2
theRecord.save()
assert theRecord["Last updated by"] == swimUser
with pytest.raises(ValueError) as excinfo:
theRecord["Last updated by"] = swimUser2
assert str(excinfo.value) == 'Input type "lastUpdatedBy" is not editable'


class TestAllUsersAndGroupsField:
Expand Down
8 changes: 8 additions & 0 deletions swimlane/core/fields/base/field.py
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,9 @@ def cast_to_bulk_modify(self, value):
return self.cast_to_report(value)

def validate_value(self, value):
"""Validate that the field is editable during set_python operation"""
self.validate_editable_field()

"""Validate value is an acceptable type during set_python operation"""
if self.readonly and not self._swimlane._write_to_read_only:
raise ValidationError(self.record, "Cannot set readonly field '{}'".format(self.name))
Expand All @@ -117,6 +120,11 @@ def validate_value(self, value):
', '.join([repr(t.__name__) for t in self.supported_types]),
type(value).__name__)
)

def validate_editable_field(self):
not_editable_input_types = ['firstCreated', 'lastUpdated', 'createdBy', 'lastUpdatedBy']
if self.input_type in not_editable_input_types:
raise ValueError('Input type "{}" is not editable'.format(self.input_type))

def _set(self, value):
"""Default setter used for both representations unless overridden"""
Expand Down
2 changes: 1 addition & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -333,7 +333,7 @@ def mock_app(mock_swimlane):
'fieldType': 'date',
'helpTextType': 'none',
'id': 'aiir8',
'inputType': 'firstCreated',
'inputType': 'dateTime',
'name': 'Incident Created'},
{'$type': 'Core.Models.Fields.UserGroupField, Core',
'controlType': 'select',
Expand Down
3 changes: 2 additions & 1 deletion tests/fields/test_basic.py
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,8 @@ def test_all_fields_empty_value(mock_record, field_class):
# Get any not readonly field instance of provided field_class
# Does not guarantee full scope of all field subtypes function as expected
for field in mock_record._fields.values():
if isinstance(field, field_class) and not field.readonly:
not_editable_input_types = ['firstCreated', 'lastUpdated', 'createdBy', 'lastUpdatedBy']
if isinstance(field, field_class) and not field.readonly and not field.input_type in not_editable_input_types:
del mock_record[field.name]

swimlane = field.get_swimlane()
Expand Down