| # Copyright 2014 the Melange authors. |
| # |
| # 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. |
| |
| """Module containing a template to display read-only sets of data.""" |
| |
| from django.template import loader |
| |
| from soc.views import template |
| from soc.views.helper import surveys |
| |
| |
| class Field(object): |
| """Class that represents a single readonly field. |
| |
| Attributs: |
| label: Label of the field. |
| value: Value of the field. |
| is_safe: Whether the value of the field is safe and can be displayed |
| on a page without being escaped. |
| """ |
| |
| def __init__(self, label, value, is_safe): |
| """Initializes a new field for the specified attributes. |
| |
| Args: |
| label: Label of the field. |
| value: Value of the field. |
| is_safe: Whether the value of the field is safe and can be displayed |
| on a page without being escaped. |
| """ |
| self.label = label |
| self.value = value |
| self.is_safe = is_safe |
| |
| |
| class Group(template.Template): |
| """Class that forms different fields together into a group. |
| |
| Attributes: |
| title: Title of the group. |
| fields: Fields that belong to the group. |
| """ |
| |
| @classmethod |
| def unsafe_from_dict(cls, data, template_path, title, as_dict): |
| """Creates a new Group based on fields which are represented by a dict. |
| |
| All fields which are included in the created group are considered unsafe, |
| i.e. the values should be escaped when rendered on the specified HTML |
| template. |
| |
| Args: |
| data: request_data.RequestData object for the current request. |
| template_path: Path to the HTML template to use for rendering. |
| title: Title of the group. |
| as_dict: A dictionary, which maps labels to values, containing fields |
| to include in the craeted group. |
| |
| Returns: |
| A newly created Group instance. |
| """ |
| return cls( |
| data, template_path, title, |
| [Field(label, value, False) for label, value in as_dict.iteritems()]) |
| |
| def __init__(self, data, template_path, title, fields): |
| """Initializes a new group for the specified attributes. |
| |
| Args: |
| data: request_data.RequestData object for the current request. |
| template_path: Path to the HTML template to use for rendering. |
| title: Title of the group. |
| fields: A list of Field instances that belong to the group. |
| """ |
| super(Group, self).__init__(data) |
| self._template_path = template_path |
| self.title = title |
| self.fields = fields |
| |
| def render(self): |
| """Renders the template as HTML. |
| |
| Returns: |
| A string containing HTML form of the template. |
| """ |
| context = { |
| 'title': self.title, |
| 'fields': self.fields, |
| } |
| return loader.render_to_string(self._template_path, dictionary=context) |
| |
| |
| class Readonly(template.Template): |
| """Template to list items in read-only manner.""" |
| |
| def __init__(self, data, template_path, groups): |
| """Initializes a new instance of this class. |
| |
| Args: |
| data: request_data.RequestData object for the current request. |
| template_path: Path to the HTML template to use for rendering. |
| groups: List of groups to include in the template. |
| """ |
| super(Readonly, self).__init__(data) |
| self._template_path = template_path |
| self._groups = groups |
| |
| def render(self): |
| """Renders the template as HTML. |
| |
| Returns: |
| A string containing HTML form of the template. |
| """ |
| context = {'groups': self._groups} |
| return loader.render_to_string(self._template_path, dictionary=context) |
| |
| |
| class ReadonlyBuilder(object): |
| """Builder to construct instances of Readonly class.""" |
| |
| def __init__(self): |
| """Initializes a new builder.""" |
| self._group_descriptors = [] |
| self._values = {} |
| self._fields_to_remove = set() |
| self._template_path = None |
| self._group_template_path = None |
| self._group_template_path_map = {} |
| |
| def addGroupDescriptor(self, group_descriptor): |
| """Updates the builder by adding a new group descriptor to the end of the |
| read-only template which is being built. |
| |
| Args: |
| group_descriptor: A GroupDescriptor to be added. |
| """ |
| self._group_descriptors.append(group_descriptor) |
| |
| def setGroupTemplatePath(self, template_path, group_id=None): |
| """Updates the builder by setting template path to render the groups. |
| |
| Args: |
| template_path: Path to the HTML template to use for rendering. |
| group_id: Optional string identifier of the group to which the template |
| path applies. |
| """ |
| if not group_id: |
| self._group_template_path = template_path |
| else: |
| self._group_template_path_map[group_id] = template_path |
| |
| def setTemplatePath(self, template_path): |
| """Updates the builder by setting template path for the read-only template. |
| |
| Args: |
| template_path: Path to the HTML template to use for rendering. |
| """ |
| self._template_path = template_path |
| |
| def setValue(self, field_id, value): |
| """Updates the builder by setting the specified value for the field with |
| the specified identifier. |
| |
| Args: |
| field_id: A string identifier of the field to set the value for. |
| value: The value to set for the field. |
| """ |
| self._values[field_id] = value |
| |
| def setValues(self, values): |
| """Updates the builder by setting the specified values. |
| |
| Args: |
| values: A dict mapping field identifiers to the corresponding values. |
| """ |
| self._values.update(values) |
| |
| def removeField(self, field_id): |
| """Removes the field with the specified identifier from the template |
| which is being built. |
| |
| Args: |
| field_id: A string identifier of the field to remove. |
| """ |
| self._fields_to_remove.add(field_id) |
| |
| def build(self, data): |
| """Builds Readonly template. |
| |
| Args: |
| data: request_data.RequestData object for the current request. |
| |
| Returns: |
| Newly created Readonly object. |
| """ |
| if not self._template_path: |
| raise ValueError('No template path set for the template') |
| |
| groups = [] |
| for group_descriptor in self._group_descriptors: |
| if group_descriptor.group_id: |
| group_template_path = self._group_template_path_map.get( |
| group_descriptor.group_id, self._group_template_path) |
| elif self._group_template_path: |
| group_template_path = self._group_template_path |
| else: |
| raise ValueError('No template path set for at least one group') |
| |
| fields = [] |
| for field_descriptor in group_descriptor.field_descriptors: |
| # skip the field if it has been removed |
| if field_descriptor.field_id in self._fields_to_remove: |
| continue |
| |
| # include the field only if the value has been set explicitly |
| if field_descriptor.field_id in self._values: |
| fields.append( |
| Field(field_descriptor.label, |
| self._values[field_descriptor.field_id], |
| field_descriptor.is_safe)) |
| |
| groups.append( |
| Group(data, group_template_path, group_descriptor.title, fields)) |
| |
| return Readonly(data, self._template_path, groups) |
| |
| |
| class GroupDescriptor(object): |
| """Descriptor of a single group to be included in Readonly template. |
| |
| Attributes: |
| title: A string containing title of the group. |
| field_descriptors: A list of FieldDescriptors to be included in the group. |
| group_id: A string containing an identifier of the group or None |
| if not specified. |
| """ |
| |
| def __init__(self, title, field_descriptors, group_id=None): |
| """Initializes a new descriptor based on the specified arguments. |
| |
| Args: |
| title: A string containing title of the group. |
| field_descriptors: A list of FieldDescriptors to be included in the group. |
| group_id: An optional string containing an identifier of the group. |
| """ |
| self.title = title |
| self.field_descriptors = field_descriptors |
| self.group_id = group_id |
| |
| |
| class SurveyGroupDescriptor(GroupDescriptor): |
| """Group descriptor for a survey.""" |
| |
| def __init__(self, title, survey, group_id=None): |
| """Initializes a new descriptor based on the specified survey. |
| |
| Args: |
| title: A string containing title of the group. |
| survey: A survey entity. |
| group_id: A string containing an optional identifier of the group. |
| """ |
| schema = surveys.SurveySchema(survey) if survey else None |
| field_descriptors = ([ |
| FieldDescriptor(question.getPropertyName(), question.getLabel()) |
| for question in schema] |
| if schema |
| else []) |
| super(SurveyGroupDescriptor, self).__init__( |
| title, field_descriptors, group_id=group_id) |
| |
| |
| class FieldDescriptor(object): |
| """Descriptor for a single field to be included in a group of Readonly |
| template. |
| """ |
| |
| def __init__(self, field_id, label, is_safe=None): |
| """Initializes a new descriptor based on the specified arguments. |
| |
| Args: |
| field_id: A string containing identifier of the field. |
| label: A string containing label of the field. |
| is_safe: Optional bool telling whether the field is safe. If specified and |
| set to True, the value of the field should not be escaped when rendered |
| on HTML template. |
| """ |
| self.field_id = field_id |
| self.label = label |
| self.is_safe = bool(is_safe) |