示例#1
0
def db_update_enabled_languages(session, tid, languages, default_language):
    """
    Transaction for updating the enabled languages for a tenant

    :param session: An ORM session
    :param tid: A tenant id
    :param languages_enabled: The list of enabled languages
    :param default_language: The language to be set as default
    """
    cur_enabled_langs = db_get_languages(session, tid)

    if len(languages) < 1:
        raise errors.InputValidationError("No languages enabled!")

    # get sure that the default language is included in the enabled languages
    languages = set(languages + [default_language])

    appdata = None
    for lang_code in languages:
        if lang_code not in LANGUAGES_SUPPORTED_CODES:
            raise errors.InputValidationError("Invalid lang code: %s" % lang_code)

        if lang_code not in cur_enabled_langs:
            if appdata is None:
                appdata = load_appdata()
            log.debug("Adding a new lang %s" % lang_code)
            models.config.add_new_lang(session, tid, lang_code, appdata)

    to_remove = list(set(cur_enabled_langs) - set(languages))
    if to_remove:
        session.query(models.User).filter(models.User.tid == tid, models.User.language.in_(to_remove)).update({'language': default_language}, synchronize_session=False)
        db_del(session, models.EnabledLanguage, (models.EnabledLanguage.tid == tid, models.EnabledLanguage.name.in_(to_remove)))
示例#2
0
def db_update_enabled_languages(session, tid, languages_enabled,
                                default_language):
    cur_enabled_langs = models.EnabledLanguage.list(session, tid)
    new_enabled_langs = [text_type(y) for y in languages_enabled]

    if len(new_enabled_langs) < 1:
        raise errors.InputValidationError("No languages enabled!")

    if default_language not in new_enabled_langs:
        raise errors.InputValidationError(
            "Invalid lang code for chosen default_language")

    appdata = None
    for lang_code in new_enabled_langs:
        if lang_code not in LANGUAGES_SUPPORTED_CODES:
            raise errors.InputValidationError("Invalid lang code: %s" %
                                              lang_code)

        if lang_code not in cur_enabled_langs:
            if appdata is None:
                appdata = load_appdata()
            log.debug("Adding a new lang %s" % lang_code)
            models.config.add_new_lang(session, tid, lang_code, appdata)

    to_remove = list(set(cur_enabled_langs) - set(new_enabled_langs))
    if to_remove:
        session.query(
            models.User).filter(models.User.tid == tid,
                                models.User.language.in_(to_remove)).update(
                                    {'language': default_language},
                                    synchronize_session='fetch')
        session.query(models.EnabledLanguage).filter(
            models.EnabledLanguage.tid == tid,
            models.EnabledLanguage.name.in_(to_remove)).delete(
                synchronize_session='fetch')
示例#3
0
def check_hostname(session, tid, input_hostname):
    """
    Ensure the hostname does not collide across tenants or include an origin
    that it shouldn't.
    """
    if input_hostname == '':
        raise errors.InputValidationError('Hostname cannot be empty')

    root_hostname = ConfigFactory(session, 1, 'node').get_val(u'hostname')

    forbidden_endings = ['onion', 'localhost']
    if tid != 1 and root_hostname != '':
        forbidden_endings.append(root_hostname)

    for v in forbidden_endings:
        if input_hostname.endswith(v):
            raise errors.InputValidationError(
                'Hostname contains a forbidden origin')

    existing_hostnames = {h.get_v() for h in session.query(Config) \
                                                    .filter(Config.tid != tid,
                                                            Config.var_name == u'hostname')}

    if input_hostname in existing_hostnames:
        raise errors.InputValidationError('Hostname already reserved')
示例#4
0
def check_field_association(session, tid, field_dict):
    if field_dict.get('fieldgroup_id', '') and session.query(
            models.Field).filter(
                models.Field.id == field_dict['fieldgroup_id'],
                models.Field.tid != tid).count():
        raise errors.InputValidationError()

    if field_dict.get('template_id',
                      '') and session.query(models.Field).filter(
                          models.Field.id == field_dict['template_id'],
                          not_(models.Field.tid.in_(set([1, tid])))).count():
        raise errors.InputValidationError()

    if field_dict.get('step_id', '') and session.query(models.Field).filter(
            models.Step.id == field_dict['step_id'], models.Questionnaire.id
            == models.Step.questionnaire_id,
            not_(models.Questionnaire.tid.in_(set([1, tid])))).count():
        raise errors.InputValidationError()

    if field_dict.get('fieldgroup_id', ''):
        ancestors = set(
            fieldtree_ancestors(session, field_dict['fieldgroup_id']))
        if field_dict['id'] == field_dict['fieldgroup_id'] or field_dict[
                'id'] in ancestors:
            raise errors.InputValidationError(
                "Provided field association would cause recursion loop")
示例#5
0
def check_hostname(session, tid, hostname):
    """
    Ensure the hostname does not collide across tenants or include an origin that it shouldn't.

    :param session: An ORM session
    :param tid: A tenant id
    :param hostname: The hostname to be evaluated
    """
    if hostname == '':
        return

    forbidden_endings = ['onion', 'localhost']

    for v in forbidden_endings:
        if hostname.endswith(v):
            raise errors.InputValidationError(
                'Hostname contains a forbidden origin')

    existing_hostnames = {
        h.value
        for h in session.query(Config).filter(Config.tid != tid,
                                              Config.var_name == 'hostname')
    }

    if hostname in existing_hostnames:
        raise errors.InputValidationError('Hostname already reserved')
示例#6
0
def check_field_association(session, tid, request):
    """
    Transaction to check consistency of field association

    :param session: The ORM session
    :param tid: The tenant ID
    :param request: The request data to be verified
    """
    if request.get('fieldgroup_id', '') and session.query(models.Field).filter(
            models.Field.id == request['fieldgroup_id'],
            models.Field.tid != tid).count():
        raise errors.InputValidationError()

    if request.get('template_id', '') and session.query(models.Field).filter(
            models.Field.id == request['template_id'],
            not_(models.Field.tid.in_(set([1, tid])))).count():
        raise errors.InputValidationError()

    if request.get('step_id', '') and session.query(models.Field).filter(
            models.Step.id == request['step_id'], models.Questionnaire.id
            == models.Step.questionnaire_id,
            not_(models.Questionnaire.tid.in_(set([1, tid])))).count():
        raise errors.InputValidationError()

    if request.get('fieldgroup_id', ''):
        ancestors = set(fieldtree_ancestors(session, request['fieldgroup_id']))
        if request['id'] == request['fieldgroup_id'] or request[
                'id'] in ancestors:
            raise errors.InputValidationError(
                "Provided field association would cause recursion loop")
示例#7
0
    def validate_message(message, message_template):
        try:
            jmessage = json.loads(message)
        except ValueError:
            raise errors.InputValidationError("Invalid JSON format")

        if BaseHandler.validate_jmessage(jmessage, message_template):
            return jmessage

        raise errors.InputValidationError("Unexpected condition!?")
示例#8
0
def db_create_field(session, tid, field_dict, language):
    """
    Create and add a new field to the session, then return the new serialized object.

    :param session: the session on which perform queries.
    :param field_dict: the field definition dict
    :param language: the language of the field definition dict
    :return: a serialization of the object
    """
    field_dict['tid'] = tid

    fill_localized_keys(field_dict, models.Field.localized_keys, language)

    check_field_association(session, tid, field_dict)

    field = models.db_forge_obj(session, models.Field, field_dict)

    if field.template_id is not None:
        # special handling of the whistleblower_identity field
        if field.template_id == 'whistleblower_identity':
            field_attrs = read_json_file(Settings.field_attrs_file)
            attrs = field_attrs.get(field.template_id, {})
            db_add_field_attrs(session, field.id, attrs)

            if field.step_id is not None:
                questionnaire = session.query(models.Questionnaire) \
                                       .filter(models.Field.id == field.id,
                                               models.Field.step_id == models.Step.id,
                                               models.Step.questionnaire_id == models.Questionnaire.id,
                                               models.Questionnaire.tid == tid).one()

                if questionnaire.enable_whistleblower_identity is False:
                    questionnaire.enable_whistleblower_identity = True
                else:
                    raise errors.InputValidationError(
                        "Whistleblower identity field already present")
            else:
                raise errors.InputValidationError(
                    "Cannot associate whistleblower identity field to a fieldgroup"
                )

    else:
        attrs = field_dict.get('attrs', [])
        options = field_dict.get('options', [])

        db_update_fieldattrs(session, tid, field.id, attrs, language)
        db_update_fieldoptions(session, tid, field.id, options, language)

    if field.instance != 'reference':
        for c in field_dict.get('children', []):
            c['tid'] = field.tid
            c['fieldgroup_id'] = field.id
            db_create_field(session, tid, c, language)

    return field
示例#9
0
    def validate_message(message, message_template):
        try:
            if isinstance(message, binary_type):
                message = message.decode('utf-8')

            jmessage = json.loads(message)
        except ValueError:
            raise errors.InputValidationError("Invalid JSON format")

        if BaseHandler.validate_jmessage(jmessage, message_template):
            return jmessage

        raise errors.InputValidationError("Unexpected condition!?")
示例#10
0
def delete_field(session, tid, field_id):
    """
    Delete the field object corresponding to field_id

    If the field has children, remove them as well.
    If the field is immediately attached to a step object, remove it as well.

    :param session: the session on which perform queries.
    :param field_id: the id corresponding to the field.
    """
    field = models.db_get(session, models.Field, models.Field.tid == tid,
                          models.Field.id == field_id)

    if not field.editable:
        raise errors.ForbiddenOperation

    if field.instance == 'template' and session.query(models.Field).filter(
            models.Field.tid == tid, models.Field.template_id
            == field.id).count():
        raise errors.InputValidationError(
            "Cannot remove the field template as it is used by one or more questionnaires"
        )

    if field.template_id == 'whistleblower_identity' and field.step_id is not None:
        session.query(models.Questionnaire) \
             .filter(models.Questionnaire.tid == tid,
                     models.Step.id == field.step_id,
                     models.Questionnaire.id == models.Step.questionnaire_id).set(enable_whistleblower_identity = False)

    session.delete(field)
示例#11
0
def db_admin_update_user(session, state, tid, user_id, request, language):
    """
    Updates the specified user.
    """
    fill_localized_keys(request, models.User.localized_keys, language)

    user = db_get_user(session, tid, user_id)

    if user.username != request['username']:
        check = session.query(models.User).filter(
            models.User.username == text_type(request['username']),
            models.UserTenant.user_id == models.User.id,
            models.UserTenant.tenant_id == tid).one_or_none()
        if check is not None:
            raise errors.InputValidationError('Username already in use')

    user.update(request)

    password = request['password']
    if password:
        user.password = security.hash_password(password, user.salt)
        user.password_change_date = datetime_now()

    # The various options related in manage PGP keys are used here.
    parse_pgp_options(state, user, request)

    if user.role == 'admin':
        db_refresh_memory_variables(session, [tid])

    return user
示例#12
0
def db_associate_context_receivers(session, context, receiver_ids):
    """
    Transaction for associating receivers to a context

    :param session: An ORM session
    :param context: The context on which associate the specified receivers
    :param receiver_ids: A list of receivers ids to be associated to the context
    """
    db_del(session, models.ReceiverContext,
           models.ReceiverContext.context_id == context.id)

    if not receiver_ids:
        return

    if not session.query(models.Context).filter(
            models.Context.id == context.id, models.Context.tid
            == models.User.tid, models.User.id.in_(receiver_ids)).count():
        raise errors.InputValidationError()

    for i, receiver_id in enumerate(receiver_ids):
        session.add(
            models.ReceiverContext({
                'context_id': context.id,
                'receiver_id': receiver_id,
                'order': i
            }))
示例#13
0
def parse_csv_ip_ranges_to_ip_networks(ip_str):
    """Takes a list of IP addresses and/or CIDRs, and converts them to a list
    of python objects"""
    ip_str = text_type(ip_str)

    ip_network_list = []

    for ip_network_str in ip_str.split(','):
        # We want to normalize to IPvXNetwork, so we can run in comparsions on
        # IP ranges for authentications. However, we may get IP addresses, CIDR
        # ranges, or garbage. Python does provide strict=True with the ipaddress
        # methods; however, it will accept any integer is which *not* what we want
        # so we need to handle this carefully.

        # If it has a /, we'll assume it's a CIDR address, otherwise, a raw IP
        try:
            if "/" in ip_network_str:
                ip_net_obj = ipaddress.ip_network(ip_network_str, strict=True)
                ip_network_list.append(ip_net_obj)
            else:
                # Let's try and see if we can work with this
                ip_addr_obj = ipaddress.ip_address(ip_network_str)

                # If we got here, it is, convert it to a proper /32 (or /128)
                cidr_len = ip_addr_obj.max_prefixlen
                ip_network = ipaddress.ip_network(ip_network_str + '/' + str(cidr_len))
                ip_network_list.append(ip_network)
        except ValueError:
            raise errors.InputValidationError("Unable to parse IP address: %s" % ip_network_str)

    return ip_network_list
示例#14
0
    def perform_action(session, tid, csr_fields):
        db_cfg = load_tls_dict(session, tid)

        pkv = tls.PrivKeyValidator()
        ok, _ = pkv.validate(db_cfg)
        if not ok:
            raise errors.InputValidationError()

        key_pair = db_cfg['ssl_key']
        try:
            csr_txt = tls.gen_x509_csr_pem(key_pair, csr_fields, Settings.csr_sign_bits)
            log.debug("Generated a new CSR")
            return csr_txt
        except Exception as e:
            log.err(e)
            raise errors.InputValidationError('CSR gen failed')
示例#15
0
def db_admin_update_user(session, tid, user_id, request, language):
    """
    Updates the specified user.
    """
    fill_localized_keys(request, models.User.localized_keys, language)

    user = db_get_user(session, tid, user_id)

    if user.username != request['username']:
        check = session.query(models.User).filter(
            models.User.username == str(request['username']),
            models.User.tid == tid).one_or_none()
        if check is not None:
            raise errors.InputValidationError('Username already in use')

    user.update(request)

    password = request['password']
    if password and not user.crypto_pub_key:
        user.hash_alg = 'ARGON2'
        user.salt = GCE.generate_salt()
        user.password = GCE.hash_password(password, user.salt)
        user.password_change_date = datetime_now()

    # The various options related in manage PGP keys are used here.
    parse_pgp_options(user, request)

    if user.role == 'admin':
        db_refresh_memory_variables(session, [tid])

    return user
示例#16
0
    def post(self, name):
        req = self.validate_message(self.request.content.read(),
                                    requests.AdminTLSCfgFileResourceDesc)

        file_res_cls = self.get_file_res_or_raise(name)

        ok = yield file_res_cls.create_file(self.request.tid, req['content'])
        if not ok:
            raise errors.InputValidationError()
示例#17
0
def db_create_user(session, state, tid, request, language):
    request['tid'] = tid

    fill_localized_keys(request, models.User.localized_keys, language)

    if request['username']:
        user = session.query(models.User).filter(
            models.User.tid == tid, models.User.username == text_type(
                request['username'])).one_or_none()
        if user is not None:
            raise errors.InputValidationError('Username already in use')

    user = models.User({
        'tid':
        tid,
        'username':
        request['username'],
        'role':
        request['role'],
        'state':
        u'enabled',
        'name':
        request['name'],
        'description':
        request['description'],
        'name':
        request['name'],
        'language':
        language,
        'password_change_needed':
        request['password_change_needed'],
        'mail_address':
        request['mail_address']
    })

    if request['password']:
        password = request['password']
    elif user.role == 'receiver':
        # code necessary because the user.role for recipient is receiver
        password = '******'
    else:
        password = user.role

    user.salt = security.generateRandomSalt()
    user.password = security.hash_password(password, user.salt)

    # The various options related in manage PGP keys are used here.
    parse_pgp_options(state, user, request)

    session.add(user)

    session.flush()

    if not request['username']:
        user.username = user.id

    return user
示例#18
0
def db_create_user(session, state, tid, request, language):
    request['tid'] = tid

    fill_localized_keys(request, models.User.localized_keys, language)

    if request['username']:
        user = session.query(models.User).filter(
            models.User.username == text_type(request['username']),
            models.UserTenant.user_id == models.User.id,
            models.UserTenant.tenant_id == tid).one_or_none()
        if user is not None:
            raise errors.InputValidationError('Username already in use')

    user = models.User({
        'tid':
        tid,
        'username':
        request['username'],
        'role':
        request['role'],
        'state':
        u'enabled',
        'name':
        request['name'],
        'description':
        request['description'],
        'language':
        language,
        'password_change_needed':
        request['password_change_needed'],
        'mail_address':
        request['mail_address'],
        'can_edit_general_settings':
        request['can_edit_general_settings']
    })

    if not request['username']:
        user.username = user.id = uuid4()

    if request['password']:
        password = request['password']
    else:
        password = u'password'

    user.salt = security.generateRandomSalt()
    user.password = security.hash_password(password, user.salt)

    # The various options related in manage PGP keys are used here.
    parse_pgp_options(state, user, request)

    session.add(user)

    session.flush()

    db_create_usertenant_association(session, user.id, tid)

    return user
示例#19
0
文件: user.py 项目: pabit/GlobaLeaks
def db_admin_update_user(session, tid, user_session, user_id, request,
                         language):
    """
    Transaction for updating an existing user

    :param session: An ORM session
    :param tid: A tenant ID
    :param user_session: The current user session
    :param user_id: The ID of the user to update
    :param request: The request data
    :param language: The language of the request
    :return: The serialized descriptor of the updated object
    """
    fill_localized_keys(request, models.User.localized_keys, language)

    user = db_get_user(session, tid, user_id)

    if user.username != request['username']:
        check = session.query(models.User).filter(
            models.User.username == request['username'],
            models.User.tid == tid).one_or_none()
        if check is not None:
            raise errors.InputValidationError('Username already in use')

    user.update(request)

    password = request['password']
    if password and (not user.crypto_pub_key or user_session.ek):
        if user.crypto_pub_key and user_session.ek:
            enc_key = GCE.derive_key(password.encode(), user.salt)
            crypto_escrow_prv_key = GCE.asymmetric_decrypt(
                user_session.cc, Base64Encoder.decode(user_session.ek))

            if tid == 1:
                user_cc = GCE.asymmetric_decrypt(
                    crypto_escrow_prv_key,
                    Base64Encoder.decode(user.crypto_escrow_bkp1_key))
            else:
                user_cc = GCE.asymmetric_decrypt(
                    crypto_escrow_prv_key,
                    Base64Encoder.decode(user.crypto_escrow_bkp2_key))

            user.crypto_prv_key = Base64Encoder.encode(
                GCE.symmetric_encrypt(enc_key, user_cc))

        if user.hash_alg != 'ARGON2':
            user.hash_alg = 'ARGON2'
            user.salt = GCE.generate_salt()

        user.password = GCE.hash_password(password, user.salt)
        user.password_change_date = datetime_now()
        user.password_change_needed = True

    # The various options related in manage PGP keys are used here.
    parse_pgp_options(user, request)

    return user_serialize_user(session, user, language)
示例#20
0
def order_elements(session, handler, req_args, *args, **kwargs):
    ctxs = session.query(models.Context).filter(models.Context.tid == handler.request.tid)

    id_dict = { ctx.id: ctx for ctx in ctxs }
    ids = req_args['ids']

    if len(ids) != len(id_dict) or set(ids) != set(id_dict):
        raise errors.InputValidationError('list does not contain all context ids')

    for i, ctx_id in enumerate(ids):
        id_dict[ctx_id].presentation_order = i
示例#21
0
    def put(self, *args, **kwargs):
        request = self.validate_message(self.request.content.read(), requests.OpsDesc)

        op_desc = self.operation_descriptors().get(request['operation'], None)
        if op_desc is None:
            raise errors.InputValidationError('Invalid command')

        func, obj_validator = op_desc
        if obj_validator is not None:
            self.validate_jmessage(request['args'], obj_validator)

        return func(self, request['args'], *args, **kwargs)
示例#22
0
def delete_field(session, tid, field_id):
    """
    Delete the field object corresponding to field_id
    """
    field = models.db_get(session, models.Field, models.Field.tid == tid, models.Field.id == field_id)

    if not field.editable:
        raise errors.ForbiddenOperation

    if field.instance == 'template' and session.query(models.Field).filter(models.Field.tid == tid, models.Field.template_id == field.id).count():
        raise errors.InputValidationError("Cannot remove the field template as it is used by one or more questionnaires")

    session.delete(field)
示例#23
0
def check_hostname(session, tid, input_hostname):
    """
    Ensure the hostname does not collide across tenants or
    include an origin that it shouldn't.
    """
    root_hostname = ConfigFactory(session, 1).get_val('hostname')

    forbidden_endings = ['onion', 'localhost']

    for v in forbidden_endings:
        if input_hostname.endswith(v):
            raise errors.InputValidationError(
                'Hostname contains a forbidden origin')

    existing_hostnames = {
        h.value
        for h in session.query(Config).filter(Config.tid != tid,
                                              Config.var_name == 'hostname')
    }

    if input_hostname in existing_hostnames:
        raise errors.InputValidationError('Hostname already reserved')
示例#24
0
def try_to_enable_https(session, tid):
    config = ConfigFactory(session, tid)

    cv = tls.ChainValidator()
    db_cfg = load_tls_dict(session, tid)
    db_cfg['https_enabled'] = False

    ok, _ = cv.validate(db_cfg)
    if not ok:
        raise errors.InputValidationError()

    config.set_val(u'https_enabled', True)
    State.tenant_cache[tid].https_enabled = True
示例#25
0
def order_elements(session, handler, req_args, *args, **kwargs):
    steps = session.query(models.Step) \
                 .filter(models.Step.questionnaire_id == req_args['questionnaire_id'],
                         models.Questionnaire.id == req_args['questionnaire_id'],
                         models.Questionnaire.tid == handler.request.tid)

    id_dict = {step.id: step for step in steps}
    ids = req_args['ids']

    if len(ids) != len(id_dict) and set(ids) != set(id_dict):
        raise errors.InputValidationError('list does not contain all context ids')

    for i, step_id in enumerate(ids):
        id_dict[step_id].presentation_order = i
示例#26
0
def db_associate_context_receivers(session, tid, context, receiver_ids):
    session.query(models.ReceiverContext).filter(models.ReceiverContext.context_id == context.id).delete(synchronize_session='fetch')

    if not receiver_ids:
        return

    if not session.query(models.Context).filter(models.Context.id == context.id,
                                                models.Context.tid == models.User.tid,
                                                models.User.id.in_(receiver_ids)).count:
        raise errors.InputValidationError()

    for i, receiver_id in enumerate(receiver_ids):
        session.add(models.ReceiverContext({'context_id': context.id,
                                            'receiver_id': receiver_id,
                                            'presentation_order': i}))
示例#27
0
def order_status_elements(session, handler, req_args, *args, **kwargs):
    """Sets the presentation order for status elements"""

    # Presentation order is ignored for statuses
    statuses = session.query(models.SubmissionStatus)\
                      .filter(models.SubmissionStatus.tid == handler.request.tid,
                              models.SubmissionStatus.system_defined == False)

    id_dict = {status.id: status for status in statuses}
    ids = req_args['ids']

    if len(ids) != len(id_dict) or set(ids) != set(id_dict):
        raise errors.InputValidationError('list does not contain all context ids')

    for i, status_id in enumerate(ids):
        id_dict[status_id].presentation_order = i
示例#28
0
def order_substatus_elements(session, handler, req_args, *args, **kwargs):
    """Sets presentation order for substatuses"""

    submission_status_id = args[0]

    substatuses = session.query(models.SubmissionSubStatus)\
                       .filter(models.SubmissionSubStatus.submissionstatus_id == submission_status_id)

    id_dict = {substatus.id: substatus for substatus in substatuses}
    ids = req_args['ids']

    if len(ids) != len(id_dict) or set(ids) != set(id_dict):
        raise errors.InputValidationError('list does not contain all context ids')

    for i, substatus_id in enumerate(ids):
        id_dict[substatus_id].presentation_order = i
示例#29
0
def order_elements(session, tid, ids, *args, **kwargs):
    """
    Transaction for reodering context elements

    :param session:  An ORM session
    :param tid: The tenant ID
    :param req_args: The request arguments
    """
    ctxs = session.query(models.Context).filter(models.Context.tid == tid)

    id_dict = {ctx.id: ctx for ctx in ctxs}

    if len(ids) != len(id_dict) or set(ids) != set(id_dict):
        raise errors.InputValidationError('list does not contain all context ids')

    for i, ctx_id in enumerate(ids):
        id_dict[ctx_id].order = i
示例#30
0
def delete_field(session, tid, field_id):
    """
    Transaction to delete a field

    :param session: An ORM session
    :param tid: The tenant ID
    :param field_id: The id of the field to be deleted
    """
    field = db_get(session,
                   models.Field,
                   (models.Field.tid == tid,
                    models.Field.id == field_id))

    if field.instance == 'template' and session.query(models.Field).filter(models.Field.tid == tid, models.Field.template_id == field.id).count():
        raise errors.InputValidationError("Cannot remove the field template as it is used by one or more questionnaires")

    session.delete(field)