-
Notifications
You must be signed in to change notification settings - Fork 1.9k
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
feat: Add complex custom form validations #7073
Merged
Merged
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,40 @@ | ||
from flask_rest_jsonapi.schema import get_relationships | ||
from sqlalchemy import inspect | ||
|
||
from app.api.helpers.errors import UnprocessableEntityError | ||
from app.models.custom_form import CustomForms | ||
|
||
|
||
def object_as_dict(obj): | ||
return {c.key: getattr(obj, c.key) for c in inspect(obj).mapper.column_attrs} | ||
|
||
|
||
def validate_custom_form_constraints(form, obj): | ||
required_form_fields = CustomForms.query.filter_by( | ||
form=form, event_id=obj.event_id, is_included=True, is_required=True | ||
) | ||
missing_required_fields = [] | ||
for field in required_form_fields.all(): | ||
if not field.is_complex: | ||
if not getattr(obj, field.identifier): | ||
missing_required_fields.append(field.identifier) | ||
else: | ||
|
||
if not (obj.complex_field_values or {}).get(field.identifier): | ||
missing_required_fields.append(field.identifier) | ||
|
||
if len(missing_required_fields) > 0: | ||
raise UnprocessableEntityError( | ||
{'pointer': '/data/attributes'}, | ||
f'Missing required fields {missing_required_fields}', | ||
) | ||
|
||
|
||
def validate_custom_form_constraints_request(form, schema, obj, data): | ||
new_obj = type(obj)(**object_as_dict(obj)) | ||
relationship_fields = get_relationships(schema) | ||
for key, value in data.items(): | ||
if hasattr(new_obj, key) and key not in relationship_fields: | ||
setattr(new_obj, key, value) | ||
|
||
validate_custom_form_constraints(form, new_obj) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -41,7 +41,7 @@ def test_edit_attendee_minimum_fields(db, client, jwt): | |
assert attendee.lastname == 'Jamal' | ||
|
||
|
||
def test_edit_attendee_required_fields(db, client, jwt): | ||
def get_simple_custom_form_attendee(db): | ||
attendee = get_minimal_attendee(db) | ||
CustomForms( | ||
event=attendee.event, | ||
|
@@ -61,12 +61,22 @@ def test_edit_attendee_required_fields(db, client, jwt): | |
) | ||
db.session.commit() | ||
|
||
return attendee | ||
|
||
|
||
def test_edit_attendee_required_fields_missing(db, client, jwt): | ||
attendee = get_simple_custom_form_attendee(db) | ||
|
||
data = json.dumps( | ||
{ | ||
'data': { | ||
'type': 'attendee', | ||
'id': str(attendee.id), | ||
"attributes": {"firstname": "Areeb", "lastname": "Jamal"}, | ||
"attributes": { | ||
"firstname": "Areeb", | ||
"lastname": "Jamal", | ||
"city": "hello@world.com", | ||
}, | ||
} | ||
} | ||
) | ||
|
@@ -93,10 +103,14 @@ def test_edit_attendee_required_fields(db, client, jwt): | |
'jsonapi': {'version': '1.0'}, | ||
} | ||
|
||
assert attendee.firstname == 'Areeb' | ||
assert attendee.lastname == 'Jamal' | ||
assert attendee.firstname != 'Areeb' | ||
assert attendee.lastname != 'Jamal' | ||
assert attendee.email is None | ||
|
||
|
||
def test_edit_attendee_required_fields_complete(db, client, jwt): | ||
attendee = get_simple_custom_form_attendee(db) | ||
|
||
data = json.dumps( | ||
{ | ||
'data': { | ||
|
@@ -129,6 +143,151 @@ def test_edit_attendee_required_fields(db, client, jwt): | |
assert attendee.tax_business_info == 'Hello' | ||
|
||
|
||
def get_complex_custom_form_attendee(db): | ||
attendee = get_minimal_attendee(db) | ||
CustomForms( | ||
event=attendee.event, | ||
form='attendee', | ||
field_identifier='jobTitle', | ||
type='text', | ||
is_included=True, | ||
is_required=True, | ||
) | ||
CustomForms( | ||
event=attendee.event, | ||
form='attendee', | ||
field_identifier='bestFriend', | ||
name='Best Friend', | ||
type='text', | ||
is_included=True, | ||
is_required=True, | ||
is_complex=True, | ||
) | ||
db.session.commit() | ||
|
||
return attendee | ||
|
||
|
||
def test_custom_form_complex_fields_missing_required(db, client, jwt): | ||
attendee = get_complex_custom_form_attendee(db) | ||
|
||
data = json.dumps( | ||
{ | ||
'data': { | ||
'type': 'attendee', | ||
'id': str(attendee.id), | ||
"attributes": {"firstname": "Areeb", "lastname": "Jamal"}, | ||
} | ||
} | ||
) | ||
|
||
response = client.patch( | ||
f'/v1/attendees/{attendee.id}', | ||
content_type='application/vnd.api+json', | ||
headers=jwt, | ||
data=data, | ||
) | ||
|
||
db.session.refresh(attendee) | ||
|
||
assert response.status_code == 422 | ||
assert json.loads(response.data) == { | ||
'errors': [ | ||
{ | ||
'detail': "Missing required fields ['best_friend', 'job_title']", | ||
'source': {'pointer': '/data/attributes'}, | ||
'status': 422, | ||
'title': 'Unprocessable Entity', | ||
} | ||
], | ||
'jsonapi': {'version': '1.0'}, | ||
} | ||
|
||
assert attendee.firstname != 'Areeb' | ||
assert attendee.lastname != 'Jamal' | ||
assert attendee.complex_field_values is None | ||
|
||
|
||
def test_custom_form_complex_fields_missing_required_one(db, client, jwt): | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. |
||
attendee = get_complex_custom_form_attendee(db) | ||
|
||
data = json.dumps( | ||
{ | ||
'data': { | ||
'type': 'attendee', | ||
'id': str(attendee.id), | ||
"attributes": { | ||
"firstname": "Areeb", | ||
"lastname": "Jamal", | ||
"job_title": "Software Engineer", | ||
"complex-field-values": {"favourite-friend": "Tester"}, | ||
}, | ||
} | ||
} | ||
) | ||
|
||
response = client.patch( | ||
f'/v1/attendees/{attendee.id}', | ||
content_type='application/vnd.api+json', | ||
headers=jwt, | ||
data=data, | ||
) | ||
|
||
db.session.refresh(attendee) | ||
|
||
assert response.status_code == 422 | ||
assert json.loads(response.data) == { | ||
'errors': [ | ||
{ | ||
'detail': "Missing required fields ['best_friend']", | ||
'source': {'pointer': '/data/attributes'}, | ||
'status': 422, | ||
'title': 'Unprocessable Entity', | ||
} | ||
], | ||
'jsonapi': {'version': '1.0'}, | ||
} | ||
|
||
assert attendee.firstname != 'Areeb' | ||
assert attendee.lastname != 'Jamal' | ||
assert attendee.complex_field_values is None | ||
|
||
|
||
def test_custom_form_complex_fields_complete(db, client, jwt): | ||
attendee = get_complex_custom_form_attendee(db) | ||
|
||
data = json.dumps( | ||
{ | ||
'data': { | ||
'type': 'attendee', | ||
'id': str(attendee.id), | ||
"attributes": { | ||
"firstname": "Areeb", | ||
"lastname": "Jamal", | ||
"job_title": "Software Engineer", | ||
"complex-field-values": {"best_friend": "Tester"}, | ||
}, | ||
} | ||
} | ||
) | ||
|
||
response = client.patch( | ||
f'/v1/attendees/{attendee.id}', | ||
content_type='application/vnd.api+json', | ||
headers=jwt, | ||
data=data, | ||
) | ||
|
||
db.session.refresh(attendee) | ||
|
||
assert response.status_code == 200 | ||
|
||
assert attendee.firstname == 'Areeb' | ||
assert attendee.lastname == 'Jamal' | ||
assert attendee.job_title == 'Software Engineer' | ||
assert attendee.complex_field_values['best_friend'] == 'Tester' | ||
|
||
|
||
def test_edit_attendee_ticket(db, client, jwt): | ||
attendee = AttendeeOrderTicketSubFactory() | ||
ticket = TicketSubFactory(event=attendee.event) | ||
|
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Black would make changes.