Source code for kadi.modules.collections.forms

# Copyright 2020 Karlsruhe Institute of Technology
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
from flask_babel import lazy_gettext as _l
from flask_login import current_user
from wtforms.validators import DataRequired

from kadi.ext.db import db
from kadi.lib.forms import DynamicMultiSelectField
from kadi.lib.forms import DynamicSelectField
from kadi.lib.forms import KadiForm
from kadi.lib.forms import SubmitField
from kadi.lib.permissions.core import get_permitted_objects
from kadi.lib.permissions.core import has_permission
from kadi.lib.resources.forms import BaseResourceForm
from kadi.lib.resources.forms import RolesField
from kadi.lib.resources.forms import TagsField
from kadi.lib.resources.forms import check_duplicate_identifier
from kadi.lib.tags.models import Tag
from kadi.modules.records.models import Record
from kadi.modules.records.models import RecordState
from kadi.modules.templates.models import Template
from kadi.modules.templates.models import TemplateType

from .models import Collection


[docs]class BaseCollectionForm(BaseResourceForm): """Base form class for use in creating or updating collections. :param collection: (optional) A collection used for prefilling the form. :param user: (optional) A user that will be used for checking various access permissions when prefilling the form. Defaults to the current user. """ identifier = BaseResourceForm.identifier_field( description=_l("Unique identifier of this collection.") ) visibility = BaseResourceForm.visibility_field( description=_l( "Public visibility automatically grants EVERY logged-in user read" " permissions for this collection." ) ) tags = TagsField( _l("Tags"), max_len=Tag.Meta.check_constraints["name"]["length"]["max"], description=_l( "An optional list of keywords further describing the collection." ), ) record_template = DynamicSelectField( _l("Default record template"), coerce=int, description=_l( "A record template that will be used as a default when adding new records" " to this collection." ), ) def _check_template_permission(self, template): return has_permission(self.user, "read", "template", template.id) def _prefill_tags(self, tags): if tags is not None: self.tags.initial = [(tag, tag) for tag in sorted(tags)] def _prefill_record_template(self, template): if template is None: return if not isinstance(template, Template): template = Template.query.get_active(template) if ( template is not None and template.type == TemplateType.RECORD and self._check_template_permission(template) ): self.record_template.initial = (template.id, f"@{template.identifier}") def __init__(self, *args, collection=None, user=None, **kwargs): self.user = user if user is not None else current_user # Prefill all simple fields directly. if collection is not None: kwargs["data"] = { "title": collection.title, "identifier": collection.identifier, "description": collection.description, "visibility": collection.visibility, } super().__init__(*args, **kwargs) # Prefill all other fields separately, also taking into account whether the form # was submitted. if self.is_submitted(): self._prefill_tags(self.tags.data) self._prefill_record_template(self.record_template.data) elif collection is not None: self._prefill_tags([tag.name for tag in collection.tags]) self._prefill_record_template(collection.record_template)
[docs]class NewCollectionForm(BaseCollectionForm): """A form for use in creating new collections. :param collection: (optional) See :class:`BaseCollectionForm`. :param user: (optional) See :class:`BaseCollectionForm`. """ records = DynamicMultiSelectField( _l("Linked records"), coerce=int, description=_l("Directly link this collection with one or more records."), ) roles = RolesField( _l("Permissions"), roles=[(r, r.capitalize()) for r in Collection.Meta.permissions["roles"]], description=_l("Directly add user or group roles to this collection."), ) submit = SubmitField(_l("Create collection")) def _prefill_records(self, records): self.records.initial = [(r.id, f"@{r.identifier}") for r in records] def __init__(self, *args, collection=None, user=None, **kwargs): user = user if user is not None else current_user super().__init__(*args, collection=collection, user=user, **kwargs) linkable_record_ids = ( get_permitted_objects(user, "link", "record") .filter(Record.state == RecordState.ACTIVE) .with_entities(Record.id) ) if self.is_submitted(): if self.records.data: records = Record.query.filter( db.and_( Record.id.in_(linkable_record_ids), Record.id.in_(self.records.data), ) ) self._prefill_records(records) self.roles.set_initial_data(user=user) elif collection is not None: records = collection.records.filter(Record.id.in_(linkable_record_ids)) self._prefill_records(records) self.roles.set_initial_data(resource=collection, user=user) def validate_identifier(self, field): # pylint: disable=missing-function-docstring check_duplicate_identifier(Collection, field.data)
[docs]class EditCollectionForm(BaseCollectionForm): """A form for use in editing existing collections. :param collection: The collection to edit, used for prefilling the form. """ submit = SubmitField(_l("Save changes")) submit_quit = SubmitField(_l("Save changes and quit")) def _check_template_permission(self, template): # See "modules.collections.core.update_collection" on why this special check is # done here. return ( has_permission(self.user, "read", "template", template.id) or self.collection.record_template == template ) def __init__(self, collection, *args, **kwargs): self.collection = collection super().__init__(*args, collection=collection, **kwargs) def validate_identifier(self, field): # pylint: disable=missing-function-docstring check_duplicate_identifier(Collection, field.data, exclude=self.collection)
[docs]class LinkRecordsForm(KadiForm): """A form for use in linking collections with records.""" records = DynamicMultiSelectField( _l("Records"), validators=[DataRequired()], coerce=int ) submit = SubmitField(_l("Link records"))
[docs]class LinkCollectionsForm(KadiForm): """A form for use in linking collections with other collections.""" collections = DynamicMultiSelectField( _l("Collections"), validators=[DataRequired()], coerce=int ) submit = SubmitField(_l("Link collections"))
[docs]class AddCollectionRolesForm(KadiForm): """A form for use in adding user or group roles to a collection.""" roles = RolesField( _l("New permissions"), roles=[(r, r.capitalize()) for r in Collection.Meta.permissions["roles"]], ) submit = SubmitField(_l("Add permissions"))
[docs]class UpdateRecordsRolesForm(KadiForm): """A form for use in updating user or group roles of linked records.""" roles = RolesField( _l("New permissions"), roles=[(r, r.capitalize()) for r in Record.Meta.permissions["roles"]], allow_none=True, ) submit = SubmitField(_l("Apply permissions"))