def setup_prerequisite(self, bot_file): InputTransformation.clear() self.bot = reset_and_setup_bots([bot_file])[0] self.user = User(platform_id=Platform.get_by(id=1, single=True).id, platform_user_ident='blablabla', last_seen=datetime.datetime.now()).add() DatabaseManager.commit()
def delete_broadcast(broadcast_id): """Delete a broadcast.""" broadcast = get_account_broadcast_by_id(broadcast_id) if broadcast.status == BroadcastStatusEnum.SENT: raise AppError(HTTPStatus.STATUS_CLIENT_ERROR, CustomError.ERR_WRONG_PARAM, 'Broadcast not deletable') broadcast.delete() DatabaseManager.commit() return jsonify(message='ok')
def setUp(self): app.config['TESTING'] = True DatabaseManager.connect() DatabaseManager.reset() app.test_client_class = BearerAuthTestClient self.app = app.test_client() self.bot_ids = [] self.broadcast_ids = [] self.setup_prerequisite()
def create_platform(): """Create a new platform.""" try: platform_json = request.json platform_json['account_id'] = g.account.id platform = parse_platform(platform_json) except Exception as e: logger.exception(e) raise AppError(HTTPStatus.STATUS_CLIENT_ERROR, CustomError.ERR_WRONG_PARAM, 'Platform definition parsing failed') DatabaseManager.commit() return jsonify(platform.to_json(['config']))
def create_broadcast(): """Create a new broadcast.""" try: broadcast_json = request.json broadcast_json['account_id'] = g.account.id broadcast = parse_broadcast(broadcast_json) except Exception as e: logger.exception(e) raise AppError(HTTPStatus.STATUS_CLIENT_ERROR, CustomError.ERR_WRONG_PARAM, 'Broadcast create request failed') DatabaseManager.commit() return jsonify(broadcast.to_json())
def deploy_bot(bot_id): bot = get_account_bot_by_id(bot_id) try: parse_bot(bot.staging, bot.id) except Exception as e: logger.exception(e) raise AppError(HTTPStatus.STATUS_CLIENT_ERROR, CustomError.ERR_WRONG_PARAM, 'Bot definition parsing failed') bot_def = BotDef.add_version(bot.id, bot.staging) bot.staging = None # Clear staging area DatabaseManager.commit() return jsonify(version=bot_def.version)
def parse_platform(platform_json, to_platform_id=None, source='platform_json'): """Parse Platform from platform definition. If *to_platform_id* is specified, update existing platform specified by *to_platform_id* instead of creating a new platform. If *to_platform_id* is a callable. The result of the call is used as the platform_id. """ validate_platform_schema(platform_json) # Validate plaform-specific schema provider = get_messaging_provider( PlatformTypeEnum(platform_json['type_enum'])) try: jsonschema.validate(platform_json['config'], provider.get_config_schema()) except jsonschema.exceptions.ValidationError: logger.error('Platform config validate failed for `%s\'!', source) raise if callable(to_platform_id): to_platform_id = to_platform_id(platform_json) bot_id = platform_json.get('bot_id') if bot_id: bot = Bot.get_by(id=bot_id, account_id=platform_json['account_id'], single=True) if not bot: raise RuntimeError('bot does not exist') if to_platform_id: # Update existing platform. logger.info(u'Updating existing Platform(id=%d, name=%s) from %s ...', to_platform_id, platform_json['name'], source) platform = Platform.get_by(id=to_platform_id, single=True) platform.bot_id = bot_id platform.name = platform_json['name'] platform.deployed = platform_json['deployed'] platform.type_enum = platform_json['type_enum'] platform.provider_ident = platform_json['provider_ident'] platform.config = platform_json['config'] else: # Create a new platform. logger.info(u'Creating new Platform(name=%s) from %s ...', platform_json['name'], source) platform = Platform(**platform_json).add() DatabaseManager.flush() return platform
def create_bot(): """Create a new bot.""" data = request.json try: jsonschema.validate(data, BOT_CREATE_SCHEMA) except Exception: raise AppError(HTTPStatus.STATUS_CLIENT_ERROR, CustomError.ERR_FORM_VALIDATION, 'schema validation fail') bot = Bot(**data).add() g.account.bots.append(bot) DatabaseManager.commit() return jsonify(bot.to_json(bot.detail_fields))
def setup_prerequisite(self): DatabaseManager.reset() self.bot = Bot(name=u'test', description=u'test', interaction_timeout=120, session_timeout=86400).add() DatabaseManager.commit() config = { 'access_token': 'EAAP0okfsZCVkBAI3BCU5s3u8O0iVFh6NAwFHa7X2bKZCGQ' 'Lw6VYeTpeTsW5WODeDbekU3ZA0JyVCBSmXq8EqwL1GDuZBO' '7aAlcNEHQ3AZBIx0ZBfFLh95TlJWlLrYetzm9owKNR8Qju8' 'HF6qra20ZC6HqNXwGpaP74knlNvQJqUmwZDZD' } platform = Platform(name=u'Test Platform', bot_id=self.bot.id, type_enum=PlatformTypeEnum.Facebook, provider_ident='1155924351125985', config=config).add() DatabaseManager.commit() self.user = User(platform_id=platform.id, platform_user_ident='1153206858057166', last_seen=datetime.datetime.now()).add() DatabaseManager.commit()
def setup_prerequisite(self): DatabaseManager.reset() self.bot = Bot(name=u'test', description=u'test', interaction_timeout=120, session_timeout=86400).add() DatabaseManager.commit() config = { 'access_token': 'iHRMgmp3zRLOc6kPCbPNMwEDHyFqLGSy0tyG3uZxnkNlhMKg' '8GVFqMGslcOkmgOAFLlBvvYuXmKF9odhXtsCm3tBxRcPryKr' 'kOvzHBcBvS2zrVGiVmZGh5EBcqazgurYMwVSdgNSrhCm/qp6' '2aR7HAdB04t89/1O/w1cDnyilFU=', 'channel_secret': '335c901df3a1969ca28a48bf6ddcc333' } platform = Platform(bot_id=self.bot.id, name=u'Line', type_enum=PlatformTypeEnum.Line, provider_ident='aitjcize.line', config=config).add() DatabaseManager.commit() self.user = User( platform_id=platform.id, platform_user_ident='U7200f33369e7e586c973c3a9df8feee4', last_seen=datetime.datetime.now()).add() DatabaseManager.commit()
def add_user(platform, sender): """Add a new user into the system.""" profile_info = get_user_profile(platform, sender) user = User(platform_id=platform.id, platform_user_ident=sender, last_seen=datetime.datetime.now(), **profile_info).add() DatabaseManager.commit() statsd.gauge('users', User.count(), tags=[config.ENV_TAG]) track( TrackingInfo.Event(sender, '%s.User' % platform.type_enum.value, 'Add', profile_info['first_name'])) return user
def test_json_serializer(self): DatabaseManager.reset() account = Account(name=u'tester', email='*****@*****.**') dt = datetime.datetime(2010, 1, 1, 0, 0, tzinfo=pytz.utc) account.created_at = dt account.__json_public__.append('created_at') d = account.to_json() self.assertEquals(d['created_at'], 1262304000) self.assertEquals(d['name'], 'tester') self.assertEquals(d['email'], '*****@*****.**')
def reset_and_setup_bots(bot_names): """Reset database and setup bots. Args: bot_names: a list of bot names to setup """ bots = [] DatabaseManager.reset() register_all_modules() for platform_name in ['dev/bb8.test.platform', 'dev/bb8.test2.platform']: parse_platform_from_file(get_platform_filename(platform_name)) for bot_name in bot_names: bots.append(parse_bot_from_file(get_bot_filename(bot_name))) return bots
def test_session_mutable_tracking(self): bot = reset_and_setup_bots(['test/simple.bot'])[0] user = User(platform_id=bot.platforms[0].id, platform_user_ident='', last_seen=datetime.datetime.now(), session=1).add() DatabaseManager.commit() self.assertNotEquals(User.get_by(id=user.id, single=True), None) s = User.get_by(id=user.id, single=True) s.session.message_sent = True DatabaseManager.commit() s = User.get_by(id=user.id, single=True) self.assertEquals(s.session.message_sent, True)
def update_bot(bot_id): """Modify a bot staging area.""" bot = get_account_bot_by_id(bot_id) try: validate_bot_schema(request.json) except Exception as e: logger.exception(e) raise AppError(HTTPStatus.STATUS_CLIENT_ERROR, CustomError.ERR_WRONG_PARAM, 'Bot definition parsing failed') bot.name = request.json['bot']['name'] bot.description = request.json['bot']['description'] bot.staging = request.json DatabaseManager.commit() return jsonify(message='ok')
def update_broadcast(broadcast_id): """Update a broadcast.""" broadcast = get_account_broadcast_by_id(broadcast_id) try: broadcast_json = request.json broadcast_json['account_id'] = g.account.id parse_broadcast(broadcast_json, broadcast.id) except BroadcastUnmodifiableError: raise AppError(HTTPStatus.STATUS_CLIENT_ERROR, CustomError.ERR_WRONG_PARAM, 'Broadcast not modifiable') except Exception as e: logger.exception(e) raise AppError(HTTPStatus.STATUS_CLIENT_ERROR, CustomError.ERR_WRONG_PARAM, 'Broadcast update request failed') DatabaseManager.commit() return jsonify(message='ok')
def test_timestamp_update(self): """Make sure the updated_at timestamp automatically updates on commit.""" account = Account(email='*****@*****.**', passwd='test_hashed').add() DatabaseManager.commit() account.refresh() self.assertEquals(account.created_at, account.updated_at) last_updated = account.updated_at time.sleep(1) account.email = '*****@*****.**' DatabaseManager.commit() account.refresh() self.assertNotEquals(last_updated, account.updated_at)
def setup_prerequisite(self): register_all_modules() self.account1 = Account( name=u'test', email='*****@*****.**').set_passwd('12345678').add() self.account2 = Account( name=u'test2', email='*****@*****.**').set_passwd('12345678').add() DatabaseManager.commit() self.login(self.account1) self.create_bot() self.create_platform('dev/bb8.test.platform') self.login(self.account2) self.create_bot() self.create_platform('dev/bb8.test2.platform') # Login back as account1 self.login(self.account1)
def setup_prerequisite(self): register_all_modules() self.account1 = Account( name=u'test', email='*****@*****.**').set_passwd('12345678').add() self.account2 = Account( name=u'test2', email='*****@*****.**').set_passwd('12345678').add() DatabaseManager.commit() self.login(self.account1) self.create_bot() self.create_broadcast(self.bot_ids[0]) self.login(self.account2) self.create_bot() self.create_broadcast(self.bot_ids[1]) # Login back as account1 self.login(self.account1)
def parse_broadcast(broadcast_json, to_broadcast_id=None): """Parse Broadcast from broadcast definition.""" validate_broadcast_schema(broadcast_json) if callable(to_broadcast_id): to_broadcast_id = to_broadcast_id(broadcast_json) # Validate that the target bot is own by the same account. bot = Bot.get_by(id=broadcast_json['bot_id'], account_id=broadcast_json['account_id'], single=True) if not bot: raise RuntimeError('bot does not exist for broadcast') if to_broadcast_id: broadcast = Broadcast.get_by(id=to_broadcast_id, single=True) if broadcast.status != BroadcastStatusEnum.QUEUED: raise BroadcastUnmodifiableError # Update existing broadcast. logger.info(u'Updating existing Broadcast(id=%d, name=%s) ...', to_broadcast_id, broadcast_json['name']) broadcast = Broadcast.get_by(id=to_broadcast_id, single=True) broadcast.bot_id = broadcast_json['bot_id'] broadcast.name = broadcast_json['name'] broadcast.messages = broadcast_json['messages'] broadcast.scheduled_time = datetime.utcfromtimestamp( broadcast_json['scheduled_time']) broadcast.status = broadcast_json.get('status', broadcast.status) else: # Create a new broadcast. logger.info(u'Creating new Broadcast(name=%s) ...', broadcast_json['name']) broadcast_json['scheduled_time'] = datetime.utcfromtimestamp( broadcast_json['scheduled_time']) broadcast = Broadcast(**broadcast_json).add() DatabaseManager.commit() schedule_broadcast(broadcast) return broadcast
def test_CollectedData_API(self): for i in range(3): CollectedDatum(user_id=self.user_1.id, key='K', value='V%d' % i).add() time.sleep(1) DatabaseManager.commit() g.user = self.user_1 self.assertEquals(CollectedData.GetLast('K'), 'V2') self.assertEquals(CollectedData.Get('K', 3), ['V2', 'V1', 'V0']) self.assertEquals(CollectedData.Get('K', 2, 1), ['V1', 'V0']) # pylint: disable=W0212 for i in range(CollectedData._MAX_RETURN_RESULTS + 10): CollectedDatum(user_id=self.user_2.id, key='K', value='V%d' % i).add() DatabaseManager.commit() g.user = self.user_2 self.assertEquals(len(CollectedData.Get('K', 110)), 100) self.assertEquals(CollectedData.Count('K'), 110)
def test_Bot_API(self): """Test Bot model APIs.""" DatabaseManager.reset() bots = reset_and_setup_bots(['test/simple.bot', 'test/postback.bot']) bot1 = bots[0] bot2 = bots[1] bot2_node_len = len(bot2.nodes) bot1.delete_all_nodes() DatabaseManager.commit() # All nodes and links related to this bot should be gone. self.assertEquals(bot1.nodes, []) # Make sure delete_all_nodes does not accidentally delete node # of other bot self.assertEquals(len(bot2.nodes), bot2_node_len) # Test bot reconstruction parse_bot_from_file(get_bot_filename('test/simple.bot'), bot1.id) DatabaseManager.commit() self.assertNotEquals(bot1.nodes, []) self.assertEquals(bot1.users, []) User(platform_id=bot1.platforms[0].id, platform_user_ident='blablabla', last_seen=datetime.datetime.now()).add() User(platform_id=bot1.platforms[1].id, platform_user_ident='blablabla2', last_seen=datetime.datetime.now()).add() DatabaseManager.commit() self.assertEquals(len(bot1.users), 2) bot1_id = bot1.id bot1.delete() DatabaseManager.commit() self.assertEquals(Bot.get_by(id=bot1_id, single=True), None)
def test_auth(self): DatabaseManager.reset() account = Account(name=u'Test Account 3', email='*****@*****.**').add() some_passwd = 'abcdefg' account.set_passwd(some_passwd) DatabaseManager.commit() account_ = Account.get_by(id=account.id, single=True) self.assertNotEquals(account_.passwd, some_passwd) self.assertEquals(account_.verify_passwd(some_passwd), True) self.assertEquals(account_.verify_passwd('should be wrong'), False) token = account_.auth_token account_t = Account.from_auth_token(token) self.assertEquals(account_.id, account_t.id) fake_token = jwt.encode({ 'iss': 'compose.ai', 'sub': account_.id, 'jti': str(uuid.uuid4()), 'iat': datetime.datetime.utcnow(), 'exp': datetime.datetime.utcnow() + datetime.timedelta(days=14) }, 'im fake secret') with self.assertRaises(RuntimeError): Account.from_auth_token(fake_token) outdated_token = jwt.encode({ 'iss': 'compose.ai', 'sub': account_.id, 'jti': str(uuid.uuid4()), 'iat': datetime.datetime.utcnow() - datetime.timedelta(days=30), 'exp': datetime.datetime.utcnow() - datetime.timedelta(days=15) }, config.JWT_SECRET) with self.assertRaises(RuntimeError): Account.from_auth_token(outdated_token)
def email_register(): data = request.json try: jsonschema.validate(data, REGISTER_SCHEMA) pytz.timezone(data['timezone']) except Exception: raise AppError(HTTPStatus.STATUS_CLIENT_ERROR, CustomError.ERR_FORM_VALIDATION, 'schema validation fail') account = Account.get_by(email=data['email'], single=True) if not account: account = Account(email=data['email']).set_passwd(data['passwd']).add() DatabaseManager.commit() else: raise AppError(HTTPStatus.STATUS_CLIENT_ERROR, CustomError.ERR_USER_EXISTED, 'email %s is already taken' % data['email']) ret = account.to_json() ret[Key.AUTH_TOKEN] = account.auth_token return jsonify(ret)
def test_query_expression_rendering(self): """Test that query expresssion can be query and rendered correctly.""" CollectedDatum(user_id=self.user_1.id, key='data', value='value1').add() DatabaseManager.commit() time.sleep(1) CollectedDatum(user_id=self.user_1.id, key='data', value='value2').add() DatabaseManager.commit() time.sleep(1) CollectedDatum(user_id=self.user_1.id, key='data', value='value3').add() CollectedDatum(user_id=self.user_1.id, key='aaa', value='aaa').add() CollectedDatum(user_id=self.user_2.id, key='data', value='value4').add() DatabaseManager.commit() g.user = self.user_1 m = Message("{{data('data').first|upper}}") self.assertEquals(m.as_dict()['text'], 'VALUE1') m = Message("{{data('data').get(1)}}") self.assertEquals(m.as_dict()['text'], 'value2') m = Message("{{data('data').last}}") self.assertEquals(m.as_dict()['text'], 'value3') m = Message("{{data('data').lru(0)}}") self.assertEquals(m.as_dict()['text'], 'value3') m = Message("{{data('data').lru(1)}}") self.assertEquals(m.as_dict()['text'], 'value2') m = Message("{{data('data').fallback('valuef').get(5)}}") self.assertEquals(m.as_dict()['text'], 'valuef') m = Message("{{data('data').order_by('-created_at').first}}") self.assertEquals(m.as_dict()['text'], 'value3') m = Message("{{data('data').count}}") self.assertEquals(m.as_dict()['text'], '3') # Test error with self.assertRaises(Exception): Message("{{data('data')|some_filter}}") wrong_tmpl = "{{data('some_key').first}}" m = Message(wrong_tmpl) self.assertEquals(m.as_dict()['text'], wrong_tmpl)
def teardown_appcontext(unused_exc): """Closes the database at the end of the request.""" DatabaseManager.disconnect(commit=config.COMMIT_ON_APP_TEARDOWN) send_ga_track_info()
def before_request(): """Make sure we are connected to the database each request.""" DatabaseManager.connect()
def parse_bot(bot_json, to_bot_id=None, source='bot_json'): """Parse Bot from bot definition. If *to_bot_id* is specified, update existing bot specified by *to_bot_id* instead of creating a new bot. If *to_bot_id* is a callable. The result of the call is used as the bot_id. """ validate_bot_schema(bot_json, source=source) bot_desc = bot_json['bot'] if callable(to_bot_id): to_bot_id = to_bot_id(bot_desc) if to_bot_id: # Update existing bot. logger.info(u'Updating existing Bot(id=%d, name=%s) from %s ...', to_bot_id, bot_desc['name'], source) bot = Bot.get_by(id=to_bot_id, single=True) bot.delete_all_nodes() bot.name = bot_desc['name'] bot.description = bot_desc['description'] bot.interaction_timeout = bot_desc['interaction_timeout'] bot.admin_interaction_timeout = bot_desc['admin_interaction_timeout'] bot.session_timeout = bot_desc['session_timeout'] bot.ga_id = bot_desc.get('ga_id', None) bot.settings = bot_desc['settings'] DatabaseManager.flush() else: # Create a new bot logger.info(u'Creating new Bot(name=%s) from %s ...', bot_desc['name'], source) bot = Bot( name=bot_desc['name'], description=bot_desc['description'], interaction_timeout=bot_desc['interaction_timeout'], admin_interaction_timeout=bot_desc['admin_interaction_timeout'], session_timeout=bot_desc['session_timeout'], ga_id=bot_desc.get('ga_id', None), settings=bot_desc['settings']).add() DatabaseManager.flush() # Bind Platform with Bot platforms = bot_json.get('platforms', {}) for unused_name, provider_ident in platforms.iteritems(): platform = Platform.get_by(provider_ident=provider_ident, single=True) if platform is None: raise RuntimeError('associated platform `%s\' does not exist', provider_ident) # Bind platform.bot_id = bot.id provider = get_messaging_provider(platform.type_enum) if not platform.deployed or (config.DEPLOY and platform.deployed): provider.apply_settings(platform.config, bot.settings) DatabaseManager.flush() nodes = bot_desc['nodes'] id_map = {} # Mapping of stable_id to id # Build node for stable_id, node in nodes.iteritems(): try: cm = ContentModule.get_by(id=node['content_module']['id'], single=True) if cm is None: raise RuntimeError('Content_module `%d\' does not exist', node['content_module']['id']) jsonschema.validate(node['content_module']['config'], cm.get_module().schema()) except jsonschema.exceptions.ValidationError: logger.error( 'Node `%s\' content module config validation ' 'failed', stable_id) raise n = Node(stable_id=stable_id, bot_id=bot.id, name=unicode(node['name']), description=unicode(node['description']), expect_input=node['expect_input'], content_module_id=node['content_module']['id'], content_config=node['content_module']['config']).add() if 'parser_module' in node: n.parser_module_id = node['parser_module']['id'] DatabaseManager.flush() id_map[stable_id] = n.id # Validate that parser module linkages are present in this bot file. for stable_id, node in nodes.iteritems(): n = Node.get_by(id=id_map[stable_id], single=True) if n.parser_module is not None: nodes = bot_json['bot']['nodes'] n.parser_config = node['parser_module']['config'] pm = n.parser_module.get_module() try: jsonschema.validate(n.parser_config, pm.schema()) except jsonschema.exceptions.ValidationError: logger.error( 'Node `%s\' parser module config validation ' 'failed', stable_id) raise for end_node_id in pm.get_linkages(n.parser_config): if end_node_id is not None: if re.search(HAS_VARIABLE_RE, end_node_id): logger.info('Rendered end_node_id `%s\', check ' 'skipped ...' % end_node_id) continue if end_node_id not in id_map.keys(): raise RuntimeError('end_node_id `%s\' is invalid' % end_node_id) DatabaseManager.flush() return bot
def tearDown(self): DatabaseManager.disconnect() self.send_message_mock.stop() # pylint: disable=E1101
def tearDown(self): DatabaseManager.disconnect()