diff --git a/run_tests.py b/run_tests.py index 58448a8..06b2b08 100644 --- a/run_tests.py +++ b/run_tests.py @@ -58,9 +58,11 @@ if __name__ == '__main__': jcl_suite = unittest.TestSuite() # jcl_suite.addTest(FeederComponent_TestCase('test_handle_tick')) -# jcl_suite.addTest(JCLComponent_TestCase('test_run_unhandled_error')) -# jcl_suite = unittest.TestSuite((component_suite)) +# jcl_suite.addTest(JCLComponent_TestCase('test_handle_get_register_exist_complex')) +# jcl_suite.addTest(AccountModule_TestCase('test_mandatory_field')) +# jcl_suite = unittest.TestSuite((account_module_suite)) # jcl_suite = unittest.TestSuite((presence_account_suite)) + jcl_suite = unittest.TestSuite((component_suite, \ feeder_component_suite, \ feeder_suite, \ @@ -69,6 +71,7 @@ if __name__ == '__main__': account_module_suite, \ account_suite, \ presence_account_suite)) + test_support.run_suite(jcl_suite) diff --git a/src/jcl/jabber/component.py b/src/jcl/jabber/component.py index 998fa18..9083f26 100644 --- a/src/jcl/jabber/component.py +++ b/src/jcl/jabber/component.py @@ -426,29 +426,34 @@ class JCLComponent(Component, object): if accounts_count >= 1: _account = list(accounts)[0] else: - if info_query.get_to().node is None: + if info_query.get_to().resource is None: if len(self.account_classes) > 1: - self.__logger.error("There should be only one account class declared") + self.__logger.error("There might be only one account class declared") new_account_class = self.account_classes[0] else: - new_account_class = self._get_account_class(info_query.get_to().node + "Account") + new_account_class = self._get_account_class(info_query.get_to().resource + "Account") _account = new_account_class(user_jid = unicode(base_from_jid), \ name = name, \ jid = name + u"@" + unicode(self.jid)) field = None try: + self.__logger.debug("Populating " + str(_account)) for (field, field_type, field_options, field_post_func, \ field_default_func) in _account.get_register_fields(): + self.__logger.debug("Testing " + field) if field is not None: if field in x_data: - setattr(_account, field, \ - field_post_func(x_data[field].value)) + value = x_data[field].value else: - setattr(_account, field, \ - field_default_func(field)) + value = None + setattr(_account, field, \ + field_post_func(value, field_default_func)) except FieldError, exception: _account.destroySelf() - self.__logger.error(str(exception)) + type, value, stack = sys.exc_info() + self.__logger.error("Error while populating account: %s\n%s" % \ + (exception, "".join(traceback.format_exception + (type, value, stack, 5)))) iq_error = info_query.make_error_response("not-acceptable") text = iq_error.get_error().xmlnode.newTextChild(None, \ "text", \ @@ -659,6 +664,7 @@ class JCLComponent(Component, object): if _account_class.__name__.lower() == account_class_name.lower(): self.__logger.debug(account_class_name + " found") return _account_class + self.__logger.debug(account_class_name + " not found") return None def _list_accounts(self, disco_items, _account_class, base_from_jid, account_type = ""): @@ -728,6 +734,7 @@ class JCLComponent(Component, object): % (exception)) self.stream.send(msg) type, value, stack = sys.exc_info() + # TODO : not checking email here self.__logger.debug("Error while first checking mail : %s\n%s" \ % (exception, "".join(traceback.format_exception (type, value, stack, 5)))) @@ -748,7 +755,11 @@ class JCLComponent(Component, object): name = "name", \ required = True) - for (field_name, field_type, field_options, post_func, default_func) in \ + for (field_name, \ + field_type, \ + field_options, \ + post_func, \ + default_func) in \ _account_class.get_register_fields(): if field_name is None: # TODO : Add page when empty tuple given @@ -760,9 +771,11 @@ class JCLComponent(Component, object): label = getattr(lang_class, lang_label_attr) else: label = field_name + self.__logger.debug("Adding field " + field_name + " to registration form") field = reg_form.add_field(field_type = field_type, \ label = label, \ - name = field_name) + name = field_name, \ + value = default_func()) if field_options is not None: for option_value in field_options: lang_label_attr = _account_class.__name__.lower() \ @@ -773,7 +786,10 @@ class JCLComponent(Component, object): label = option_value field.add_option(label = label, \ values = [option_value]) - if default_func == account.mandatory_field: + try: + post_func(None, default_func) + except: + self.__logger.debug("Setting field " + field_name + " required") field.required = True ## TODO : get default value if any return reg_form diff --git a/src/jcl/model/account.py b/src/jcl/model/account.py index 9994187..8509f7f 100644 --- a/src/jcl/model/account.py +++ b/src/jcl/model/account.py @@ -37,25 +37,25 @@ OFFLINE = "offline" ONLINE = "online" -def default_post_func(field_value): +def default_post_func(field_value, default_func): """Default post process function: do nothing""" + if field_value is None or str(field_value) == "": + return default_func() return field_value -def int_post_func(field_value): +def int_post_func(field_value, default_func): """Return an integer from integer field value""" + if field_value is None or str(field_value) == "": + return int(default_func()) return int(field_value) -def string_not_null_post_func(field_value): - """Post process function for not null/empty string""" - if field_value is None or field_value == "": +def mandatory_field(field_name, field_value, default_func): + """Used as default function for field that must be specified + and cannot have an empty value""" + if field_value is None or str(field_value) == "": raise FieldError # TODO : add translated message return field_value -def mandatory_field(field_name): - """Used as default function for field that must be specified - and cannot have default value""" - raise FieldError # TODO : add translated message - # create a hub to attach a per thread connection hub = ConnectionHub() @@ -119,8 +119,7 @@ class Account(InheritableSQLObject): 'list-single', ... - field_options: - field_post_func: function called to process received field - - field_default_func: function to return default value (or error if - field is mandatory) + - field_default_func: function to return default value """ return [] # "name" field is mandatory @@ -184,32 +183,55 @@ class PresenceAccount(Account): def _get_register_fields(cls): """ See Account._get_register_fields """ - def is_action_possible(action): - if int(action) in cls.possibles_actions: - return int(action) - raise FieldError # TODO : add translated message + def get_possibles_actions(presence_action_field): + return cls.get_presence_actions_fields()[presence_action_field][0] - # TODO : check is_action_possible with presence_actions_fields (see partial eval function) + def is_action_possible(presence_action_field, action, default_func): + if int(action) in get_possibles_actions(presence_action_field): + return int(action) + raise default_func() + + def get_default_presence_action(presence_action_field): + return cls.get_presence_actions_fields()[presence_action_field][1] + return Account.get_register_fields() + \ [(None, None, None, None, None), \ ("chat_action", "list-single", \ - [str(action) for action in cls.possibles_actions], \ - is_action_possible, mandatory_field), \ + [str(action) for action in get_possibles_actions("chat_action")], \ + lambda action, default_func: is_action_possible("chat_action", \ + action, \ + default_func), \ + lambda : get_default_presence_action("chat_action")), \ ("online_action", "list-single", \ - [str(action) for action in cls.possibles_actions], \ - is_action_possible, mandatory_field), \ + [str(action) for action in get_possibles_actions("online_action")], \ + lambda action, default_func: is_action_possible("online_action", \ + action, \ + default_func), \ + lambda : get_default_presence_action("online_action")), \ ("away_action", "list-single", \ - [str(action) for action in cls.possibles_actions], \ - is_action_possible, mandatory_field), \ + [str(action) for action in get_possibles_actions("away_action")], \ + lambda action, default_func: is_action_possible("away_action", \ + action, \ + default_func), \ + lambda : get_default_presence_action("away_action")), \ ("xa_action", "list-single", \ - [str(action) for action in cls.possibles_actions], \ - is_action_possible, mandatory_field), \ + [str(action) for action in get_possibles_actions("xa_action")], \ + lambda action, default_func: is_action_possible("xa_action", \ + action, \ + default_func), \ + lambda : get_default_presence_action("xa_action")), \ ("dnd_action", "list-single", \ - [str(action) for action in cls.possibles_actions], \ - is_action_possible, mandatory_field), \ + [str(action) for action in get_possibles_actions("dnd_action")], \ + lambda action, default_func: is_action_possible("dnd_action", \ + action, \ + default_func), \ + lambda : get_default_presence_action("dnd_action")), \ ("offline_action", "list-single", \ - [str(action) for action in cls.possibles_actions], \ - is_action_possible, mandatory_field)] + [str(action) for action in get_possibles_actions("offline_action")], \ + lambda action, default_func: is_action_possible("offline_action", \ + action, \ + default_func), \ + lambda : get_default_presence_action("offline_action"))] get_register_fields = classmethod(_get_register_fields) diff --git a/tests/jcl/jabber/test_component.py b/tests/jcl/jabber/test_component.py index 23eb651..3afcd0b 100644 --- a/tests/jcl/jabber/test_component.py +++ b/tests/jcl/jabber/test_component.py @@ -894,6 +894,63 @@ class JCLComponent_TestCase(unittest.TestCase): self.assertEquals(presence_account.get_node().prop("type"), \ "subscribe") + def test_handle_set_register_new_multiple_types(self): + self.comp.stream = MockStream() + self.comp.stream_class = MockStream + self.comp.account_classes = [ExampleAccount, Example2Account] + x_data = Form("submit") + x_data.add_field(name = "name", \ + value = "account1", \ + field_type = "text-single") + iq_set = Iq(stanza_type = "set", \ + from_jid = "user1@test.com", \ + to_jid = "jcl.test.com/Example2") + query = iq_set.new_query("jabber:iq:register") + x_data.as_xml(query, None) + self.comp.handle_set_register(iq_set) + + account.hub.threadConnection = connectionForURI('sqlite://' + DB_URL) + accounts = self.comp.account_classes[1].select(\ + self.comp.account_classes[1].q.user_jid == "user1@test.com" \ + and self.comp.account_classes[1].q.name == "account1") + self.assertEquals(accounts.count(), 1) + _account = accounts[0] + self.assertEquals(_account.user_jid, "user1@test.com") + self.assertEquals(_account.name, "account1") + self.assertEquals(_account.jid, "account1@jcl.test.com") + del account.hub.threadConnection + + stanza_sent = self.comp.stream.sent + self.assertEquals(len(stanza_sent), 4) + iq_result = stanza_sent[0] + self.assertTrue(isinstance(iq_result, Iq)) + self.assertEquals(iq_result.get_node().prop("type"), "result") + self.assertEquals(iq_result.get_from(), "jcl.test.com/Example2") + self.assertEquals(iq_result.get_to(), "user1@test.com") + + presence_component = stanza_sent[1] + self.assertTrue(isinstance(presence_component, Presence)) + self.assertEquals(presence_component.get_from(), "jcl.test.com") + self.assertEquals(presence_component.get_to(), "user1@test.com") + self.assertEquals(presence_component.get_node().prop("type"), \ + "subscribe") + + message = stanza_sent[2] + self.assertTrue(isinstance(message, Message)) + self.assertEquals(message.get_from(), "jcl.test.com") + self.assertEquals(message.get_to(), "user1@test.com") + self.assertEquals(message.get_subject(), \ + _account.get_new_message_subject(Lang.en)) + self.assertEquals(message.get_body(), \ + _account.get_new_message_body(Lang.en)) + + presence_account = stanza_sent[3] + self.assertTrue(isinstance(presence_account, Presence)) + self.assertEquals(presence_account.get_from(), "account1@jcl.test.com") + self.assertEquals(presence_account.get_to(), "user1@test.com") + self.assertEquals(presence_account.get_node().prop("type"), \ + "subscribe") + def test_handle_set_register_new_complex(self): self.comp.stream = MockStream() self.comp.stream_class = MockStream diff --git a/tests/jcl/model/account.py b/tests/jcl/model/account.py index 1288db1..77fb2f5 100644 --- a/tests/jcl/model/account.py +++ b/tests/jcl/model/account.py @@ -38,23 +38,26 @@ class ExampleAccount(Account): test_int = IntCol(default = 42) def _get_register_fields(cls): - def password_post_func(password): + def password_post_func(password, default_func): if password is None or password == "": return None return password - + return Account.get_register_fields() + \ - [("login", "text-single", None, account.string_not_null_post_func, \ - account.mandatory_field), \ + [("login", "text-single", None, \ + lambda field_value, default_func: account.mandatory_field("login", \ + field_value, \ + default_func), \ + lambda : ""), \ ("password", "text-private", None, password_post_func, \ - (lambda field_name: None)), \ + lambda : ""), \ ("store_password", "boolean", None, account.default_post_func, \ - lambda field_name: True), \ + lambda : True), \ ("test_enum", "list-single", ["choice1", "choice2", "choice3"], \ - account.string_not_null_post_func,\ - lambda field_name: "choice2"), \ + account.default_post_func, \ + lambda : "choice2"), \ ("test_int", "text-single", None, account.int_post_func, \ - lambda field_name: 44)] + lambda : 44)] get_register_fields = classmethod(_get_register_fields) @@ -64,7 +67,7 @@ class Example2Account(Account): def _get_register_fields(cls): return Account.get_register_fields() + \ [("test_new_int", "text-single", None, account.int_post_func, \ - lambda field_name: 43)] + lambda : 43)] get_register_fields = classmethod(_get_register_fields) class PresenceAccountExample(PresenceAccount): diff --git a/tests/jcl/model/test_account.py b/tests/jcl/model/test_account.py index d8bb8fb..9779de4 100644 --- a/tests/jcl/model/test_account.py +++ b/tests/jcl/model/test_account.py @@ -38,31 +38,42 @@ DB_URL = DB_PATH# + "?debug=1&debugThreading=1" class AccountModule_TestCase(unittest.TestCase): def test_default_post_func(self): - result = account.default_post_func("test") + result = account.default_post_func("test", None) + self.assertEquals(result, "test") + + def test_default_post_func_default_value(self): + result = account.default_post_func("", lambda : "test") + self.assertEquals(result, "test") + + def test_default_post_func_default_value2(self): + result = account.default_post_func(None, lambda : "test") self.assertEquals(result, "test") def test_int_post_func(self): - result = account.int_post_func("42") + result = account.int_post_func("42", None) self.assertEquals(result, 42) - def test_string_not_null_post_func_not_null(self): - result = account.string_not_null_post_func("ok") - self.assertEquals(result, "ok") + def test_int_post_func_default_value(self): + result = account.int_post_func("", lambda : 42) + self.assertEquals(result, 42) - def test_string_not_null_post_func_none(self): - self.assertRaises(FieldError, \ - account.string_not_null_post_func, \ - None) + def test_int_post_func_default_value(self): + result = account.int_post_func(None, lambda : 42) + self.assertEquals(result, 42) - def test_string_not_null_post_func_empty(self): - self.assertRaises(FieldError, \ - account.string_not_null_post_func, \ - "") - - def test_mandatory_field(self): + def test_mandatory_field_empty(self): self.assertRaises(FieldError, \ account.mandatory_field, \ - "") + "field", "", None) + + def test_mandatory_field_none(self): + self.assertRaises(FieldError, \ + account.mandatory_field, \ + "field", None, None) + + def test_mandatory_field_empty(self): + self.assertEquals(account.mandatory_field("field", "value", None), \ + "value") class Account_TestCase(unittest.TestCase): def setUp(self): @@ -146,9 +157,14 @@ class PresenceAccount_TestCase(unittest.TestCase): user_jid = "test1@test.com", \ name = "account11", \ jid = "account11@jcl.test.com") - self.assertEquals(account11.possibles_actions, PresenceAccountExample.possibles_actions) - (possibles_actions, chat_default_action) = account11.get_presence_actions_fields()["chat_action"] - self.assertEquals(chat_default_action, PresenceAccountExample.DO_SOMETHING_ELSE) - self.assertEquals(possibles_actions, PresenceAccountExample.possibles_actions) + for (field_name, \ + field_type, \ + possibles_actions, \ + post_func, \ + default_func) in account11.get_register_fields()[1:]: + for possible_action in possibles_actions: + self.assertEquals(post_func(possible_action, default_func), + int(possible_action)) + self.assertTrue(str(default_func()) in possibles_actions) del account.hub.threadConnection