Philipp Hörist pushed to branch master at gajim / gajim
Commits: 8ce0c62c by Philipp Hörist at 2019-06-28T21:38:13Z Remove outdated comment
- - - - - 9caa3aad by Philipp Hörist at 2019-06-28T21:47:21Z Use nbxmpp's dataforms module
- - - - - 20301d36 by Philipp Hörist at 2019-06-28T21:47:25Z Remove unused dataforms module
This was a copy of nbxmpp's dataforms module
- - - - -
12 changed files:
- gajim/common/caps_cache.py - gajim/common/connection_handlers_events.py - gajim/common/modules/adhoc_commands.py - − gajim/common/modules/dataforms.py - gajim/common/modules/pubsub.py - gajim/dataforms_widget.py - gajim/gtk/account_wizard.py - gajim/gtk/adhoc.py - gajim/gtk/dataform.py - gajim/gtk/search.py - gajim/gtk/service_registration.py - test/gtk/dataform.py
Changes:
===================================== gajim/common/caps_cache.py ===================================== @@ -105,9 +105,6 @@ def create_suitable_client_caps(node, caps_hash, hash_method, fjid=None): def compute_caps_hash(identities, features, dataforms=None, hash_method='sha-1'): """ Compute caps hash according to XEP-0115, V1.5 - - dataforms are nbxmpp.DataForms objects as common.dataforms don't allow several - values without a field type list-multi """ if dataforms is None: dataforms = []
===================================== gajim/common/connection_handlers_events.py ===================================== @@ -21,6 +21,7 @@ import logging
import OpenSSL.crypto import nbxmpp +from nbxmpp.modules import dataforms
from gajim.common import nec from gajim.common import helpers @@ -28,7 +29,6 @@ from gajim.common import app from gajim.common import i18n from gajim.common.i18n import _ from gajim.common.helpers import AdditionalDataDict -from gajim.common.modules import dataforms from gajim.common.const import KindConstant, SSLError from gajim.common.jingle_transport import JingleTransportSocks5 from gajim.common.file_props import FilesProp
===================================== gajim/common/modules/adhoc_commands.py ===================================== @@ -21,12 +21,12 @@
import nbxmpp from nbxmpp.structs import StanzaHandler +from nbxmpp.modules import dataforms
from gajim.common import app from gajim.common import helpers from gajim.common.i18n import _ from gajim.common.nec import NetworkIncomingEvent -from gajim.common.modules import dataforms from gajim.common.modules.base import BaseModule
===================================== gajim/common/modules/dataforms.py deleted ===================================== @@ -1,760 +0,0 @@ -# Copyright (C) 2006-2007 Tomasz Melcer <liori AT exroot.org> -# Copyright (C) 2006-2014 Yann Leboulanger <asterix AT lagaule.org> -# Copyright (C) 2007 Stephan Erb <steve-e AT h3c.de> -# -# This file is part of Gajim. -# -# Gajim is free software; you can redistribute it and/or modify -# it under the terms of the GNU General Public License as published -# by the Free Software Foundation; version 3 only. -# -# Gajim is distributed in the hope that it will be useful, -# but WITHOUT ANY WARRANTY; without even the implied warranty of -# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -# GNU General Public License for more details. -# -# You should have received a copy of the GNU General Public License -# along with Gajim. If not, see http://www.gnu.org/licenses/. - -# XEP-0004: Data Forms - -import nbxmpp - -from gajim.common import helpers - - -# exceptions used in this module -class Error(Exception): - pass - - -# when we get nbxmpp.Node which we do not understand -class UnknownDataForm(Error): - pass - - -# when we get nbxmpp.Node which contains bad fields -class WrongFieldValue(Error): - pass - - -# helper class to change class of already existing object -class ExtendedNode(nbxmpp.Node): - @classmethod - def __new__(cls, *args, **kwargs): - if 'extend' not in kwargs.keys() or not kwargs['extend']: - return object.__new__(cls) - - extend = kwargs['extend'] - assert issubclass(cls, extend.__class__) - extend.__class__ = cls - return extend - - -# helper to create fields from scratch -def create_field(typ, **attrs): - ''' Helper function to create a field of given type. ''' - field = { - 'boolean': BooleanField, - 'fixed': StringField, - 'hidden': StringField, - 'text-private': StringField, - 'text-single': StringField, - 'jid-multi': JidMultiField, - 'jid-single': JidSingleField, - 'list-multi': ListMultiField, - 'list-single': ListSingleField, - 'text-multi': TextMultiField, - }[typ](typ=typ, **attrs) - return field - - -def extend_field(node): - """ - Helper function to extend a node to field of appropriate type - """ - # when validation (XEP-122) will go in, we could have another classes - # like DateTimeField - so that dicts in create_field() and - # extend_field() will be different... - typ = node.getAttr('type') - field = { - 'boolean': BooleanField, - 'fixed': StringField, - 'hidden': StringField, - 'text-private': StringField, - 'text-single': StringField, - 'jid-multi': JidMultiField, - 'jid-single': JidSingleField, - 'list-multi': ListMultiField, - 'list-single': ListSingleField, - 'text-multi': TextMultiField, - } - if typ not in field: - typ = 'text-single' - return field[typ](extend=node) - - -def extend_form(node): - """ - Helper function to extend a node to form of appropriate type - """ - if node.getTag('reported') is not None: - return MultipleDataForm(extend=node) - return SimpleDataForm(extend=node) - - -class DataField(ExtendedNode): - """ - Keeps data about one field - var, field type, labels, instructions... Base - class for different kinds of fields. Use create_field() function to construct one - of these - """ - - def __init__(self, typ=None, var=None, value=None, label=None, desc=None, - required=False, options=None, extend=None): - - if extend is None: - ExtendedNode.__init__(self, 'field') - - self.type_ = typ - self.var = var - if value is not None: - self.value = value - if label is not None: - self.label = label - if desc is not None: - self.desc = desc - self.required = required - self.options = options - - @property - def type_(self): - """ - Type of field. Recognized values are: 'boolean', 'fixed', 'hidden', - 'jid-multi', 'jid-single', 'list-multi', 'list-single', 'text-multi', - 'text-private', 'text-single'. If you set this to something different, - DataField will store given name, but treat all data as text-single - """ - type_ = self.getAttr('type') - if type_ is None: - return 'text-single' - return type_ - - @type_.setter - def type_(self, value): - assert isinstance(value, str) - self.setAttr('type', value) - - @property - def var(self): - """ - Field identifier - """ - return self.getAttr('var') - - @var.setter - def var(self, value): - assert isinstance(value, str) - self.setAttr('var', value) - - @var.deleter - def var(self): - self.delAttr('var') - - @property - def label(self): - """ - Human-readable field name - """ - label_ = self.getAttr('label') - if not label_: - label_ = self.var - return label_ - - @label.setter - def label(self, value): - assert isinstance(value, str) - self.setAttr('label', value) - - @label.deleter - def label(self): - if self.getAttr('label'): - self.delAttr('label') - - @property - def description(self): - """ - Human-readable description of field meaning - """ - return self.getTagData('desc') or '' - - @description.setter - def description(self, value): - assert isinstance(value, str) - if value == '': - del self.description - else: - self.setTagData('desc', value) - - @description.deleter - def description(self): - desc = self.getTag('desc') - if desc is not None: - self.delChild(desc) - - @property - def required(self): - """ - Controls whether this field required to fill. Boolean - """ - return bool(self.getTag('required')) - - @required.setter - def required(self, value): - required = self.getTag('required') - if required and not value: - self.delChild(required) - elif not required and value: - self.addChild('required') - - @property - def media(self): - """ - Media data - """ - media = self.getTag('media', namespace=nbxmpp.NS_DATA_MEDIA) - if media: - return Media(media) - - @media.setter - def media(self, value): - del self.media - self.addChild(node=value) - - @media.deleter - def media(self): - media = self.getTag('media') - if media is not None: - self.delChild(media) - - @staticmethod - def is_valid(): - return True, '' - - -class Uri(nbxmpp.Node): - def __init__(self, uri_tag): - nbxmpp.Node.__init__(self, node=uri_tag) - - @property - def type_(self): - """ - uri type - """ - return self.getAttr('type') - - @type_.setter - def type_(self, value): - self.setAttr('type', value) - - @type_.deleter - def type_(self): - self.delAttr('type') - - @property - def uri_data(self): - """ - uri data - """ - return self.getData() - - @uri_data.setter - def uri_data(self, value): - self.setData(value) - - @uri_data.deleter - def uri_data(self): - self.setData(None) - - -class Media(nbxmpp.Node): - def __init__(self, media_tag): - nbxmpp.Node.__init__(self, node=media_tag) - - @property - def uris(self): - """ - URIs of the media element. - """ - return map(Uri, self.getTags('uri')) - - @uris.setter - def uris(self, value): - del self.uris - for uri in value: - self.addChild(node=uri) - - @uris.deleter - def uris(self): - for element in self.getTags('uri'): - self.delChild(element) - - -class BooleanField(DataField): - @property - def value(self): - """ - Value of field. May contain True, False or None - """ - value = self.getTagData('value') - if value in ('0', 'false'): - return False - if value in ('1', 'true'): - return True - if value is None: - return False # default value is False - raise WrongFieldValue - - @value.setter - def value(self, value): - self.setTagData('value', value and '1' or '0') - - @value.deleter - def value(self): - value = self.getTag('value') - if value is not None: - self.delChild(value) - - -class StringField(DataField): - """ - Covers fields of types: fixed, hidden, text-private, text-single - """ - - @property - def value(self): - """ - Value of field. May be any string - """ - return self.getTagData('value') or '' - - @value.setter - def value(self, value): - assert isinstance(value, str) - if value == '' and not self.required: - del self.value - return - self.setTagData('value', value) - - @value.deleter - def value(self): - try: - self.delChild(self.getTag('value')) - except ValueError: # if there already were no value tag - pass - - def is_valid(self): - if not self.required: - return True, '' - if not self.value: - return False, '' - return True, '' - - -class ListField(DataField): - """ - Covers fields of types: jid-multi, jid-single, list-multi, list-single - """ - - @property - def options(self): - """ - Options - """ - options = [] - for element in self.getTags('option'): - value = element.getTagData('value') - if value is None: - raise WrongFieldValue - label = element.getAttr('label') - if not label: - label = value - options.append((label, value)) - return options - - @options.setter - def options(self, values): - del self.options - for value, label in values: - self.addChild('option', - {'label': label}).setTagData('value', value) - - @options.deleter - def options(self): - for element in self.getTags('option'): - self.delChild(element) - - def iter_options(self): - for element in self.iterTags('option'): - value = element.getTagData('value') - if value is None: - raise WrongFieldValue - label = element.getAttr('label') - if not label: - label = value - yield (value, label) - - -class ListSingleField(ListField, StringField): - """ - Covers list-single field - """ - def is_valid(self): - if not self.required: - return True, '' - if not self.value: - return False, '' - return True, '' - - -class JidSingleField(ListSingleField): - """ - Covers jid-single fields - """ - def is_valid(self): - if self.value: - try: - helpers.parse_jid(self.value) - return True, '' - except Exception as error: - return False, error - if self.required: - return False, '' - return True, '' - - -class ListMultiField(ListField): - """ - Covers list-multi fields - """ - - @property - def values(self): - """ - Values held in field - """ - values = [] - for element in self.getTags('value'): - values.append(element.getData()) - return values - - @values.setter - def values(self, values): - del self.values - for value in values: - self.addChild('value').setData(value) - - @values.deleter - def values(self): - for element in self.getTags('value'): - self.delChild(element) - - def iter_values(self): - for element in self.getTags('value'): - yield element.getData() - - def is_valid(self): - if not self.required: - return True, '' - if not self.values: - return False, '' - return True, '' - - -class JidMultiField(ListMultiField): - """ - Covers jid-multi fields - """ - def is_valid(self): - if self.values: - for value in self.values: - try: - helpers.parse_jid(value) - except Exception as error: - return False, error - return True, '' - if self.required: - return False, '' - return True, '' - - -class TextMultiField(DataField): - @property - def value(self): - """ - Value held in field - """ - value = '' - for element in self.iterTags('value'): - value += '\n' + element.getData() - return value[1:] - - @value.setter - def value(self, value): - del self.value - if value == '': - return - for line in value.split('\n'): - self.addChild('value').setData(line) - - @value.deleter - def value(self): - for element in self.getTags('value'): - self.delChild(element) - - def is_valid(self): - if not self.required: - return True, '' - if not self.value: - return False, '' - return True, '' - - -class DataRecord(ExtendedNode): - """ - The container for data fields - an xml element which has DataField elements - as children - """ - def __init__(self, fields=None, associated=None, extend=None): - self.associated = associated - self.vars = {} - if extend is None: - # we have to build this object from scratch - nbxmpp.Node.__init__(self) - - if fields is not None: - self.fields = fields - else: - # we already have nbxmpp.Node inside - try to convert all - # fields into DataField objects - if fields is None: - for field in self.iterTags('field'): - if not isinstance(field, DataField): - extend_field(field) - self.vars[field.var] = field - else: - for field in self.getTags('field'): - self.delChild(field) - self.fields = fields - - @property - def fields(self): - """ - List of fields in this record - """ - return self.getTags('field') - - @fields.setter - def fields(self, fields): - del self.fields - for field in fields: - if not isinstance(field, DataField): - extend_field(field) - self.addChild(node=field) - - @fields.deleter - def fields(self): - for element in self.getTags('field'): - self.delChild(element) - - def iter_fields(self): - """ - Iterate over fields in this record. Do not take associated into account - """ - for field in self.iterTags('field'): - yield field - - def iter_with_associated(self): - """ - Iterate over associated, yielding both our field and associated one - together - """ - for field in self.associated.iter_fields(): - yield self[field.var], field - - def __getitem__(self, item): - return self.vars[item] - - def is_valid(self): - for field in self.iter_fields(): - if not field.is_valid()[0]: - return False - return True - - -class DataForm(ExtendedNode): - def __init__(self, type_=None, title=None, instructions=None, extend=None): - if extend is None: - # we have to build form from scratch - nbxmpp.Node.__init__(self, 'x', attrs={'xmlns': nbxmpp.NS_DATA}) - - if type_ is not None: - self.type_ = type_ - if title is not None: - self.title = title - if instructions is not None: - self.instructions = instructions - - @property - def type_(self): - """ - Type of the form. Must be one of: 'form', 'submit', 'cancel', 'result'. - 'form' - this form is to be filled in; you will be able soon to do: - filledform = DataForm(replyto=thisform) - """ - return self.getAttr('type') - - @type_.setter - def type_(self, type_): - assert type_ in ('form', 'submit', 'cancel', 'result') - self.setAttr('type', type_) - - @property - def title(self): - """ - Title of the form - - Human-readable, should not contain any \r\n. - """ - return self.getTagData('title') - - @title.setter - def title(self, title): - self.setTagData('title', title) - - @title.deleter - def title(self): - try: - self.delChild('title') - except ValueError: - pass - - @property - def instructions(self): - """ - Instructions for this form - - Human-readable, may contain \r\n. - """ - # TODO: the same code is in TextMultiField. join them - value = '' - for valuenode in self.getTags('instructions'): - value += '\n' + valuenode.getData() - return value[1:] - - @instructions.setter - def instructions(self, value): - del self.instructions - if value == '': - return - for line in value.split('\n'): - self.addChild('instructions').setData(line) - - @instructions.deleter - def instructions(self): - for value in self.getTags('instructions'): - self.delChild(value) - - @property - def is_reported(self): - return self.getTag('reported') is not None - - -class SimpleDataForm(DataForm, DataRecord): - def __init__(self, type_=None, title=None, instructions=None, fields=None, - extend=None): - DataForm.__init__(self, type_=type_, title=title, - instructions=instructions, extend=extend) - DataRecord.__init__(self, fields=fields, extend=self, associated=self) - - def get_purged(self): - simple_form = SimpleDataForm(extend=self) - del simple_form.title - simple_form.instructions = '' - to_be_removed = [] - for field in simple_form.iter_fields(): - if field.required: - # add <value> if there is not - if hasattr(field, 'value') and not field.value: - field.value = '' - # Keep all required fields - continue - if ((hasattr(field, 'value') and - not field.value and - field.value != 0) or - (hasattr(field, 'values') and not field.values)): - to_be_removed.append(field) - else: - del field.label - del field.description - del field.media - for field in to_be_removed: - simple_form.delChild(field) - return simple_form - - -class MultipleDataForm(DataForm): - def __init__(self, type_=None, title=None, instructions=None, items=None, - extend=None): - DataForm.__init__(self, type_=type_, title=title, - instructions=instructions, extend=extend) - # all records, recorded into DataRecords - if extend is None: - if items is not None: - self.items = items - else: - # we already have nbxmpp.Node inside - try to convert all - # fields into DataField objects - if items is None: - self.items = list(self.iterTags('item')) - else: - for item in self.getTags('item'): - self.delChild(item) - self.items = items - reported_tag = self.getTag('reported') - self.reported = DataRecord(extend=reported_tag) - - @property - def items(self): - """ - A list of all records - """ - return list(self.iter_records()) - - @items.setter - def items(self, records): - del self.items - for record in records: - if not isinstance(record, DataRecord): - DataRecord(extend=record) - self.addChild(node=record) - - @items.deleter - def items(self): - for record in self.getTags('item'): - self.delChild(record) - - def iter_records(self): - for record in self.getTags('item'): - yield record - -# -# @reported.setter -# def reported(self, record): -# try: -# self.delChild('reported') -# except Exception: -# pass -# -# record.setName('reported') -# self.addChild(node=record)
===================================== gajim/common/modules/pubsub.py ===================================== @@ -21,9 +21,9 @@ # XEP-0060: Publish-Subscribe
import nbxmpp +from nbxmpp.modules import dataforms
from gajim.common import app -from gajim.common.modules import dataforms from gajim.common.nec import NetworkIncomingEvent from gajim.common.modules.base import BaseModule
===================================== gajim/dataforms_widget.py ===================================== @@ -30,8 +30,9 @@ from gi.repository import GdkPixbuf from gi.repository import GObject from gi.repository import GLib
+from nbxmpp.modules import dataforms + from gajim import gtkgui_helpers -from gajim.common.modules import dataforms from gajim.common import helpers from gajim.common import app from gajim.common.i18n import _
===================================== gajim/gtk/account_wizard.py ===================================== @@ -18,13 +18,14 @@ from gi.repository import Gtk from gi.repository import Gdk from gi.repository import GLib
+from nbxmpp.modules import dataforms + from gajim.common import app from gajim.common import ged from gajim.common import configpaths from gajim.common import helpers from gajim.common import connection from gajim.common.i18n import _ -from gajim.common.modules import dataforms
from gajim import dataforms_widget from gajim import gui_menu_builder
===================================== gajim/gtk/adhoc.py ===================================== @@ -16,14 +16,14 @@ import logging from enum import IntEnum
from gi.repository import Gtk + from nbxmpp.util import is_error_result from nbxmpp.const import AdHocAction +from nbxmpp.modules import dataforms
from gajim.common import app from gajim.common.i18n import _
-from gajim.common.modules import dataforms - from gajim.gtk.dataform import DataFormWidget from gajim.gtk.util import ensure_not_destroyed from gajim.gtk.util import find_widget
===================================== gajim/gtk/dataform.py ===================================== @@ -17,12 +17,13 @@ from gi.repository import GLib from gi.repository import GObject from gi.repository import Pango
+from nbxmpp.modules.dataforms import extend_form + from gajim.gtkgui_helpers import scale_pixbuf_from_data
from gajim.common import app from gajim.common.i18n import _ from gajim.common.helpers import open_uri -from gajim.common.modules.dataforms import extend_form
from gajim.gtk.util import MultiLineLabel from gajim.gtk.util import MaxWidthComboBoxText
===================================== gajim/gtk/search.py ===================================== @@ -20,12 +20,12 @@ from enum import IntEnum
from gi.repository import Gtk
+from nbxmpp.modules import dataforms + from gajim.common import app from gajim.common import ged from gajim.common.i18n import _
-from gajim.common.modules import dataforms - from gajim.gui_menu_builder import SearchMenu
from gajim.gtk.dataform import DataFormWidget
===================================== gajim/gtk/service_registration.py ===================================== @@ -17,8 +17,9 @@ from enum import IntEnum
from gi.repository import Gtk
+from nbxmpp.modules import dataforms + from gajim.common import app -from gajim.common.modules import dataforms from gajim.common.i18n import _
from gajim.gtk.dataform import DataFormWidget
===================================== test/gtk/dataform.py ===================================== @@ -2,9 +2,9 @@ from base64 import b64decode
from gi.repository import Gtk import nbxmpp +from nbxmpp.modules.dataforms import extend_form
from gajim.gtk.dataform import DataFormWidget -from gajim.common.modules.dataforms import extend_form from gajim.common.const import CSSPriority from gajim.common import app
View it on GitLab: https://dev.gajim.org/gajim/gajim/compare/9c53fcbd898bd0d61e5d16f8eac586fda8...