The invenio domains create command allows creating domains with duplicate labels, which should be rejected. This causes multiple entries in the database. When selecting one of the duplicate domain labels in the domain administration UI, it results in a 500 error:
sqlalchemy.exc.MultipleResultsFound error due to non-unique entries.
Steps to Reproduce
Run invenio domains create company.
Run invenio domains create company again.
Attempt to select the "company" domain in the domain administration UI.
Observe the error.
Expected behavior
The system should prevent creating domains with duplicate labels, returning an error instead of creating the domain.
Screenshots (if applicable)
Logs
127.0.0.1 - - [20/Aug/2024 13:36:06] "POST /api/domains HTTP/1.1" 500 -
Traceback (most recent call last):
File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/flask/app.py", line 2552, in __call__
return self.wsgi_app(environ, start_response)
File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/werkzeug/middleware/proxy_fix.py", line 187, in __call__
return self.app(environ, start_response)
File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/werkzeug/middleware/dispatcher.py", line 78, in __call__
return app(environ, start_response)
File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/flask/app.py", line 2552, in __call__
return self.wsgi_app(environ, start_response)
File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/werkzeug/middleware/proxy_fix.py", line 187, in __call__
return self.app(environ, start_response)
File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/flask/app.py", line 2532, in wsgi_app
response = self.handle_exception(e)
File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/flask/app.py", line 2529, in wsgi_app
response = self.full_dispatch_request()
File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/flask/app.py", line 1825, in full_dispatch_request
rv = self.handle_user_exception(e)
File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/flask/app.py", line 1823, in full_dispatch_request
rv = self.dispatch_request()
File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/flask/app.py", line 1799, in dispatch_request
return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/flask_resources/resources.py", line 65, in view
return view_meth()
File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/flask_resources/content_negotiation.py", line 116, in inner_content_negotiation
return f(*args, **kwargs)
File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/flask_resources/parsers/decorators.py", line 51, in inner
return f(self, *args, **kwargs)
File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/flask_resources/parsers/decorators.py", line 90, in inner
return f(self, *args, **kwargs)
File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/flask_resources/responses.py", line 39, in inner
res = f(*args, **kwargs)
File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/invenio_records_resources/resources/records/resource.py", line 93, in create
item = self.service.create(
File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/invenio_records_resources/services/uow.py", line 376, in inner
res = f(self, *args, **kwargs)
File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/invenio_records_resources/services/records/service.py", line 327, in create
return self._create(self.record_cls, identity, data, uow=uow, expand=expand)
File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/invenio_records_resources/services/uow.py", line 380, in inner
return f(self, *args, **kwargs)
File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/invenio_records_resources/services/records/service.py", line 342, in _create
data, errors = self.schema.load(
File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/invenio_records_resources/services/records/schema.py", line 90, in load
valid_data = self.schema(context=context, **schema_args).load(data)
File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/marshmallow/schema.py", line 722, in load
return self._do_load(
File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/marshmallow/schema.py", line 884, in _do_load
self._invoke_schema_validators(
File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/marshmallow/schema.py", line 1184, in _invoke_schema_validators
self._run_validator(
File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/marshmallow/schema.py", line 774, in _run_validator
validator_func(output, partial=partial, many=many)
File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/invenio_users_resources/services/schemas.py", line 277, in validate_category
category = DomainCategory.get(data["category_name"])
File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/invenio_accounts/models.py", line 541, in get
return cls.query.filter_by(label=label).one_or_none()
File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/sqlalchemy/orm/query.py", line 2850, in one_or_none
return self._iter().one_or_none()
File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/sqlalchemy/engine/result.py", line 1510, in one_or_none
return self._only_one_row(
File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/sqlalchemy/engine/result.py", line 614, in _only_one_row
raise exc.MultipleResultsFound(
sqlalchemy.exc.MultipleResultsFound: Multiple rows were found when one or none was required
Package version (if known): 12
Describe the bug
The
invenio domains create
command allows creating domains with duplicate labels, which should be rejected. This causes multiple entries in the database. When selecting one of the duplicate domain labels in the domain administration UI, it results in a 500 error:sqlalchemy.exc.MultipleResultsFound error due to non-unique entries.
Steps to Reproduce
invenio domains create company
.invenio domains create company
again.Expected behavior
The system should prevent creating domains with duplicate labels, returning an error instead of creating the domain.
Screenshots (if applicable)
Logs
127.0.0.1 - - [20/Aug/2024 13:36:06] "POST /api/domains HTTP/1.1" 500 - Traceback (most recent call last): File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/flask/app.py", line 2552, in __call__ return self.wsgi_app(environ, start_response) File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/werkzeug/middleware/proxy_fix.py", line 187, in __call__ return self.app(environ, start_response) File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/werkzeug/middleware/dispatcher.py", line 78, in __call__ return app(environ, start_response) File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/flask/app.py", line 2552, in __call__ return self.wsgi_app(environ, start_response) File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/werkzeug/middleware/proxy_fix.py", line 187, in __call__ return self.app(environ, start_response) File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/flask/app.py", line 2532, in wsgi_app response = self.handle_exception(e) File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/flask/app.py", line 2529, in wsgi_app response = self.full_dispatch_request() File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/flask/app.py", line 1825, in full_dispatch_request rv = self.handle_user_exception(e) File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/flask/app.py", line 1823, in full_dispatch_request rv = self.dispatch_request() File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/flask/app.py", line 1799, in dispatch_request return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args) File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/flask_resources/resources.py", line 65, in view return view_meth() File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/flask_resources/content_negotiation.py", line 116, in inner_content_negotiation return f(*args, **kwargs) File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/flask_resources/parsers/decorators.py", line 51, in inner return f(self, *args, **kwargs) File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/flask_resources/parsers/decorators.py", line 90, in inner return f(self, *args, **kwargs) File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/flask_resources/responses.py", line 39, in inner res = f(*args, **kwargs) File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/invenio_records_resources/resources/records/resource.py", line 93, in create item = self.service.create( File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/invenio_records_resources/services/uow.py", line 376, in inner res = f(self, *args, **kwargs) File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/invenio_records_resources/services/records/service.py", line 327, in create return self._create(self.record_cls, identity, data, uow=uow, expand=expand) File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/invenio_records_resources/services/uow.py", line 380, in inner return f(self, *args, **kwargs) File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/invenio_records_resources/services/records/service.py", line 342, in _create data, errors = self.schema.load( File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/invenio_records_resources/services/records/schema.py", line 90, in load valid_data = self.schema(context=context, **schema_args).load(data) File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/marshmallow/schema.py", line 722, in load return self._do_load( File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/marshmallow/schema.py", line 884, in _do_load self._invoke_schema_validators( File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/marshmallow/schema.py", line 1184, in _invoke_schema_validators self._run_validator( File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/marshmallow/schema.py", line 774, in _run_validator validator_func(output, partial=partial, many=many) File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/invenio_users_resources/services/schemas.py", line 277, in validate_category category = DomainCategory.get(data["category_name"]) File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/invenio_accounts/models.py", line 541, in get return cls.query.filter_by(label=label).one_or_none() File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/sqlalchemy/orm/query.py", line 2850, in one_or_none return self._iter().one_or_none() File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/sqlalchemy/engine/result.py", line 1510, in one_or_none return self._only_one_row( File "/home/user/.pyenv/versions/3.9.19/envs/my-site/lib/python3.9/site-packages/sqlalchemy/engine/result.py", line 614, in _only_one_row raise exc.MultipleResultsFound( sqlalchemy.exc.MultipleResultsFound: Multiple rows were found when one or none was requiredAdditional context
Looking here shouldn't the label be unique true?