def test_replication_link(self, _input, expected, mock_circlecore): schema = Schema.create(display_name='Schema', properties='x:int,y:float') module = Module.create(display_name='Module') box = MessageBox(uuid=generate_uuid(model=MessageBox), schema_uuid=schema.uuid, module_uuid=module.uuid, display_name='Box') with MetaDataSession.begin(): MetaDataSession.add(schema) MetaDataSession.add(module) MetaDataSession.add(box) replication_link = ReplicationLink.create(message_box_uuids=[box.uuid], **_input) with MetaDataSession.begin(): MetaDataSession.add(replication_link) replication_link = ReplicationLink.query.get(replication_link.uuid) assert isinstance(replication_link, ReplicationLink) assert replication_link.display_name == expected['display_name'] assert replication_link.memo == expected['memo']
def make_own_cc_info(self, config_uuid: 'UUIDLike') -> CcInfo: """自身のCircleCore Infoを作成する. Args: config_uuid (str): uuid, autoの場合は生成する Returns: circle_core.models.CcInfo: 自身のCircleCore Info """ with MetaDataSession.begin(): try: my_cc_info = CcInfo.query.filter_by(myself=True).one() except NoResultFound: logger.info('My CCInfo not found. Create new one') my_cc_info = CcInfo(display_name='My CircleCore', myself=True, work='') if config_uuid == 'auto': my_cc_info.uuid = generate_uuid(model=CcInfo) else: my_cc_info.uuid = config_uuid MetaDataSession.add(my_cc_info) return my_cc_info
async def on_slave_hello(self, json_msg): """hello コマンドが送られてきた""" assert self.state == ReplicationState.HANDSHAKING self.state = ReplicationState.MIGRATING # slave's cc info slave_info = json_msg['ccInfo'] slave_uuid = uuid.UUID(slave_info['uuid']) with MetaDataSession.begin(): # store slave's information if slave_uuid not in [ slave.slave_uuid for slave in self.replication_link.slaves ]: self.replication_link.slaves.append( ReplicationSlave(link_uuid=self.replication_link.uuid, slave_uuid=slave_uuid)) cc_info = CcInfo.query.get(slave_uuid) if not cc_info: cc_info = CcInfo(uuid=slave_uuid, myself=False) cc_info.update_from_json(slave_info) MetaDataSession.add(cc_info) await self.send_migrate()
def test_user(self, _input, expected, mock_circlecore): user = User.create(**_input) with MetaDataSession.begin(): MetaDataSession.add(user) user = User.query.get(user.uuid) assert isinstance(user, User) assert user.account == expected['account'] assert user.is_password_matched(expected['password']) is True assert user.is_password_matched(expected['password_no_match']) is False assert len(user.permissions) == len(expected['permissions']) for permission, exp_permission in zip(user.permissions, expected['permissions']): assert isinstance(permission, str) assert permission == exp_permission assert user.work == expected['work'] assert user.mail_address == expected['mail_address'] assert user.telephone == expected['telephone'] assert user.is_admin() == ('admin' in expected['permissions']) jsonobj = user.to_json(full=True) assert str(user.uuid) == jsonobj['uuid'] assert user.account == jsonobj['account'] assert user.work == jsonobj['work'] assert user.mail_address == jsonobj['mailAddress'] assert user.telephone == jsonobj['telephone'] assert len(user.permissions) == len(jsonobj['permissions']) for permission, exp_permission in zip(user.permissions, jsonobj['permissions']): assert permission == exp_permission
def test_moge(self): """API認証""" with MetaDataSession.begin(): user = User.create(account='tester', password='******') user.renew_token() schema = Schema.create(display_name='Schema', properties='x:int,y:float,data:blob') module = Module.create(display_name='Module') mbox = MessageBox(uuid='4ffab839-cf56-478a-8614-6003a5980857', schema_uuid=schema.uuid, module_uuid=module.uuid) MetaDataSession.add(user) MetaDataSession.add(schema) MetaDataSession.add(module) MetaDataSession.add(mbox) data_api_endpoint = self.get_url('/api/modules/{}/{}/data'.format( module.uuid, mbox.uuid)) # 認証がいるよ response = self.fetch(data_api_endpoint) assert response.code == 403 # 認証がいるよ response = self.fetch( data_api_endpoint, headers={'Authorization': 'Bearer {}'.format(user.encoded_token)}) assert response.code == 200
def test_rest(self): """登録されているModuleからのPOSTは404""" # make dummy environ with MetaDataSession.begin(): user = User.create(account='tester', password='******') user.renew_token() schema = Schema.create(display_name='Schema', properties='x:int,y:float') module = Module.create(display_name='Module') mbox = MessageBox( uuid='4ffab839-cf56-478a-8614-6003a5980856', schema_uuid=schema.uuid, module_uuid=module.uuid ) MetaDataSession.add(user) MetaDataSession.add(schema) MetaDataSession.add(module) MetaDataSession.add(mbox) response = self.fetch( self.get_url('/modules/{}/{}'.format(module.uuid, mbox.uuid)), method='POST', body=json.dumps({ 'x': 1, 'y': 2.5 }), headers={ 'Content-Type': 'application/json', 'Authorization': 'Bearer {token}'.format(token=user.encoded_token), } ) self.assertEqual(response.code, 200) self.datareceiver.receive_new_message.assert_called_once_with(str(mbox.uuid), {'x': 1, 'y': 2.5})
def test_check_match(self, _input, data, expected, mock_circlecore): jsonobj = dict(displayName='Schema', memo='memo', properties=_input) schema = Schema.create() schema.update_from_json(jsonobj) with MetaDataSession.begin(): MetaDataSession.add(schema) schema = Schema.query.get(schema.uuid) ok, msg = schema.check_match(data) assert ok is expected
def _delete_invitation(invitation): """Invitationを削除する. :param Invitation invitation: 削除するInvitation :return: Invitationの情報 :rtype: Response """ with MetaDataSession.begin(): MetaDataSession.delete(invitation) return respond_success(invitation={'uuid': invitation.uuid})
def _delete_replication_master(replication_master): """ReplicationMasterを削除する. :param ReplicationMaster replication_master: 削除するReplicationMaster :return: ReplicationMasterの情報 :rtype: Response """ with MetaDataSession.begin(): MetaDataSession.delete(replication_master) return respond_success(replicationMaster=replication_master.to_json())
def _delete_replica(replication_link): """ReplicationLinkを削除する. :param ReplicationLink replication_link: 削除するReplicationLink :return: ReplicationLinkの情報 :rtype: Response """ with MetaDataSession.begin(): MetaDataSession.delete(replication_link) return respond_success(replicationLink=replication_link.to_json())
def _put_core(cc_info): """CircleCoreを更新する. :param CcInfo cc_info: 更新するCircleCore :return: CircleCoreの情報 :rtype: Response """ with MetaDataSession.begin(): cc_info.update_from_json(request.json) MetaDataSession.add(cc_info) return respond_success(ccInfo=cc_info.to_json())
def _post_schemas(): """Schemaを作成する. :return: 作成したSchemaの情報 :rtype: Response """ with MetaDataSession.begin(): schema = Schema.create() schema.update_from_json(request.json) MetaDataSession.add(schema) return respond_success(schema=schema.to_json(with_modules=True))
async def on_master_migrate(self, message): assert self.state == ReplicationState.MIGRATING with MetaDataSession.begin(): # save master info data = message['masterInfo'] try: obj = CcInfo.query.filter_by(uuid=data['uuid']).one() except NoResultFound: obj = CcInfo(uuid=data['uuid'], myself=False) obj.update_from_json(data) obj.replication_master_id = self.master.id MetaDataSession.add(obj) master_info = obj self.master.master_uuid = master_info.uuid # migrate schemas for schema_uuid, data in message['schemas'].items(): try: obj = Schema.query.filter_by(uuid=data['uuid']).one() except NoResultFound: obj = Schema(uuid=data['uuid']) obj.update_from_json(data) obj.cc_uuid = master_info.uuid MetaDataSession.add(obj) # migrate modules for module_uuid, data in message['modules'].items(): try: obj = Module.query.filter_by(uuid=data['uuid']).one() except NoResultFound: obj = Module(uuid=data['uuid']) obj.update_from_json(data) obj.cc_uuid = master_info.uuid obj.replication_master_id = self.master.id MetaDataSession.add(obj) # migrate boxes self.target_boxes = {} for box_uuid, data in message['messageBoxes'].items(): try: obj = MessageBox.query.filter_by(uuid=data['uuid']).one() if obj.schema_uuid != uuid.UUID(data['schemaUuid']): raise DataConfilictedError('schemaUuid not match') if obj.module_uuid != uuid.UUID(data['moduleUuid']): raise DataConfilictedError('moduleUuid not match') except NoResultFound: obj = MessageBox( uuid=data['uuid'], schema_uuid=data['schemaUuid'], module_uuid=data['moduleUuid'], ) obj.update_from_json(data) MetaDataSession.add(obj) self.target_boxes[obj.uuid] = obj
def check_login(): """ログイン確認.""" user = get_user_from_request() if not user: raise abort(403) # update user's last access from circle_core.models import MetaDataSession with MetaDataSession.begin(): user.last_access_at = datetime.utcnow() MetaDataSession.add(user)
def _delete_module(module): """Moduleを削除する. :param Module module: 削除するModule :return: Moduleの情報 :rtype: Response """ with MetaDataSession.begin(): if module.replication_master is not None: MetaDataSession.delete(module.replication_master) else: MetaDataSession.delete(module) return respond_success(module={'uuid': module.uuid})
def _post_invitation(): """Invitationを作成する. :return: 作成したInvitationの情報 :rtype: Response """ # maxInvites項目しか許可しない with MetaDataSession.begin(): obj = Invitation(uuid=generate_uuid(model=Invitation), max_invites=request.json['maxInvites'], created_at=datetime.datetime.utcnow()) MetaDataSession.add(obj) return respond_success(invitation=obj.to_json())
def _delete_user(user): """Userを削除する. :param User user: 削除するUser :return: Userの情報 :rtype: Response """ # 自分は削除できない if user.uuid == request.oauth.user.uuid: return respond_failure('Cannot delete yourself.') with MetaDataSession.begin(): MetaDataSession.delete(user) return respond_success(user={'uuid': user.uuid})
def _post_replicas(): """ReplicationLinkを作成する. :return: 作成したReplicationLinkの情報 :rtype: Response """ data = request.json with MetaDataSession.begin(): replication_link = ReplicationLink.create( data['displayName'], data['memo'], data['messageBoxes'], ) MetaDataSession.add(replication_link) return respond_success(replicationLink=replication_link.to_json())
def test_invitation(self, _input, expected, mock_circlecore): invitation = Invitation(uuid=generate_uuid(model=Invitation), **_input) with MetaDataSession.begin(): MetaDataSession.add(invitation) invitation = Invitation.query.get(invitation.uuid) assert isinstance(invitation, Invitation) assert invitation.max_invites == expected['max_invites'] assert invitation.current_invites == expected['current_invites'] for i in range(_input['max_invites']): assert invitation.can_invite() is True invitation.inc_invites() else: assert invitation.can_invite() is False
def _post_replication_masters(): """ReplicationMasterを作成する. :return: 作成したReplicationMasterの情報 :rtype: Response """ data = request.json try: with MetaDataSession.begin(): replication_master = ReplicationMaster( endpoint_url=data['endpointUrl'], ) MetaDataSession.add(replication_master) except sqlalchemy.exc.IntegrityError: return respond_failure('このURLは既に登録されています') return respond_success(replicationMaster=replication_master.to_json())
def _put_module(module): """Moduleを更新する. :param Module module: 更新するModule :return: Moduleの情報 :rtype: Response """ try: with MetaDataSession.begin(): module.update_from_json(request.json, with_boxes=True) MetaDataSession.add(module) except KeyError: return respond_failure('key error') except ValueError as e: return respond_failure(str(e)) return respond_success(module=module.to_json(with_boxes=True, with_schema=True))
def test_message_box(self, _input, expected, mock_circlecore): schema = Schema.create(display_name='Schema', properties='x:int,y:float') module = Module.create(display_name='Module') box = MessageBox(uuid=generate_uuid(model=MessageBox), schema_uuid=schema.uuid, module_uuid=module.uuid, **_input) with MetaDataSession.begin(): MetaDataSession.add(schema) MetaDataSession.add(module) MetaDataSession.add(box) box = MessageBox.query.get(box.uuid) assert isinstance(box, MessageBox) assert box.display_name == expected['display_name'] assert box.memo == expected['memo'] assert isinstance(hash(box), int) assert isinstance(box.cc_uuid, uuid.UUID) jsonobj = box.to_json(with_schema=True, with_module=True) assert str(box.uuid) == jsonobj['uuid'] assert box.display_name == jsonobj['displayName'] assert box.memo == jsonobj['memo'] assert str(box.module_uuid) == jsonobj['moduleUuid'] assert str(box.schema_uuid) == jsonobj['schemaUuid'] assert schema.display_name == jsonobj['schema']['displayName'] assert module.display_name == jsonobj['module']['displayName']
async def test_post_date(mysql, mock_circlecore): mbox_id = uuid.uuid4() with MetaDataSession.begin(): schema = Schema.create(display_name='Schema', properties='date:datetime,id1:float') module = Module.create(display_name='Module') mbox = MessageBox(uuid=mbox_id, schema_uuid=schema.uuid, module_uuid=module.uuid) MetaDataSession.add(schema) MetaDataSession.add(module) MetaDataSession.add(mbox) envdir = mock_circlecore[1] database = Database(mysql.url, time_db_dir=envdir, log_dir=envdir) journal_writer = database.make_writer() queued_writer = journal_writer.child_writer run_loop = asyncio.ensure_future(journal_writer.run()) # post message = ModuleMessage(mbox.uuid, 123456.789, 0, { 'date': '2017-09-01T24:00:00Z', 'id1': 3.14 }) await queued_writer.store(mbox, message) await queued_writer.flush() # close database await journal_writer.close() await run_loop with database._engine.begin() as connection: table = database.find_table_for_message_box(mbox) rows = connection.execute(select([table])).fetchall() assert len(rows) == 0
def _post_modules() -> 'Response': """Moduleを作成する. :return: 作成したModuleの情報 :rtype: Response """ try: with MetaDataSession.begin(): module = Module.create() module.update_from_json(request.json, with_boxes=True) MetaDataSession.add(module) except KeyError: raise return respond_failure('key error', _status=400) return respond_success(module=module.to_json(with_boxes=True, with_schema=True))
def test_cc_info(self, _input, expected, mock_circlecore): other_cc_info = CcInfo(**_input) with MetaDataSession.begin(): MetaDataSession.add(other_cc_info) own_cc_info = CcInfo.query.filter_by(myself=True).all() assert len(own_cc_info) == 1 other_cc_info = CcInfo.query.get(_input['uuid']) assert isinstance(other_cc_info, CcInfo) assert other_cc_info.display_name == expected['display_name'] assert str(other_cc_info.uuid).lower() == expected['uuid'].lower() assert other_cc_info.myself == expected['myself'] assert other_cc_info.work == expected['work'] jsonobj = other_cc_info.to_json() assert str(other_cc_info.uuid) == jsonobj['uuid'] assert other_cc_info.display_name == jsonobj['displayName'] assert other_cc_info.work == jsonobj['work'] assert other_cc_info.myself == jsonobj['myself']
def _delete_schema(schema_uuid): """Schemaを削除する. :param str schema_uuid: 削除するSchemaのUUID :return: Schemaの情報 :rtype: Response """ schema = Schema.query.get(schema_uuid) if not schema: return respond_failure('not found', _status=404) if len(schema.message_boxes) > 0: reason = 'message box {uuids} {verb} attached'.format( uuids=', '.join([str(box.uuid) for box in schema.message_boxes]), verb='is' if len(schema.message_boxes) == 1 else 'are') return respond_failure(reason, _status=400) with MetaDataSession.begin(): MetaDataSession.delete(schema) return respond_success(schema={'uuid': schema_uuid})
def test_rest_not_found(self): """登録されていないModuleからのPOSTは404""" with MetaDataSession.begin(): user = User.create(account='tester', password='******') user.renew_token() MetaDataSession.add(user) response = self.fetch( self.get_url('/modules/4ffab839-cf56-478a-8614-6003a5980855/00000000-0000-0000-0000-000000000000'), method='POST', body=json.dumps({ 'x': 1, 'y': 2 }), headers={ 'Content-Type': 'application/json', 'Authorization': 'Bearer {token}'.format(token=user.encoded_token), } ) self.assertEqual(response.code, 404)
def test_update_from_json(self, _input, expected, mock_circlecore): schema = Schema.create(display_name='Schema', properties='x:int,y:float') module = Module.create(display_name='Module') box = MessageBox(uuid=generate_uuid(model=MessageBox), schema_uuid=schema.uuid, module_uuid=module.uuid, display_name='MessageBoxOldName') with MetaDataSession.begin(): MetaDataSession.add(schema) MetaDataSession.add(module) MetaDataSession.add(box) box = MessageBox.query.get(box.uuid) box.update_from_json(_input) with MetaDataSession.begin(): MetaDataSession.add(box) box = MessageBox.query.get(box.uuid) assert isinstance(box, MessageBox) assert box.display_name == expected['display_name'] assert box.memo == expected['memo']
def invitation_endpoint(link_uuid: 'uuid.UUID'): """User招待リンク. Args: link_uuid: User招待リンクのUUID """ invitation = Invitation.query.get(link_uuid) if not invitation or not invitation.can_invite(): raise abort(404) error = None user = None is_completed = False if request.method == 'POST': form = request.form try: with MetaDataSession.begin(): user = User.create( account=form['account'], work=form['work'], telephone=form['telephone'], mail_address=form['mailAddress'], ) user.set_password(form['password']) invitation.inc_invites() MetaDataSession.add(user) MetaDataSession.add(invitation) except sqlalchemy.exc.IntegrityError: error = 'このアカウントはすでに使われています。' except ValueError as exc: error = str(exc) else: is_completed = True return render_template( 'invitation.html', error=error, user=user.to_json() if user else None, is_completed=is_completed )
def _put_user(user): """Userを更新する. :param User user: 更新するUser :return: Userの情報 :rtype: Response """ has_write, req = oauth.verify_request([CRScope.USER_RW.value]) # TODO: viewでやるな # validation errors = {} if not has_write: # Read権限のみでは、自分の情報しか変更できない、currentPasswordが必要、permissionの変更はできない if user.uuid != request.oauth.user.uuid: return respond_failure('no permission.', _status=400) if 'currentPassword' in request.json: if not user.is_password_matched(request.json['currentPassword']): errors['currentPassword'] = u'現在のパスワードが間違っています' else: if 'newPassword' in request.json: return respond_failure( 'user+r scope cannot change password without current.', _status=400) if 'permissions' in request.json: return respond_failure( 'user+r scope cannot change mine permission.', _status=400) if 'newPassword' in request.json: if not request.json['newPassword']: errors['newPassword'] = u'新しいパスワードが空欄です' if len(request.json['newPassword']) < 6: errors['newPassword'] = u'パスワードは6文字以上にしてください' if not request.json['account']: errors['account'] = u'アカウントは空には出来ません' if errors: return respond_failure('パラメータにエラーがあります', _status=400, errors=errors) # update with MetaDataSession.begin(): user.update_from_json(request.json) respond_full = request.oauth.user.is_admin( ) or user.uuid == request.oauth.user.uuid return respond_success(user=user.to_json(respond_full))