| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152 | # -*- coding:utf-8 -*-from flask import current_appfrom flask_login import login_required, current_userfrom flask_restful import Resource, reqparse, marshal_with, abort, fields, marshalimport servicesfrom controllers.console import apifrom controllers.console.setup import setup_requiredfrom controllers.console.wraps import account_initialization_requiredfrom libs.helper import TimestampFieldfrom extensions.ext_database import dbfrom models.account import Account, TenantAccountJoinfrom services.account_service import TenantService, RegisterServiceaccount_fields = {    'id': fields.String,    'name': fields.String,    'avatar': fields.String,    'email': fields.String,    'last_login_at': TimestampField,    'created_at': TimestampField,    'role': fields.String,    'status': fields.String,}account_list_fields = {    'accounts': fields.List(fields.Nested(account_fields))}class MemberListApi(Resource):    """List all members of current tenant."""    @setup_required    @login_required    @account_initialization_required    @marshal_with(account_list_fields)    def get(self):        members = TenantService.get_tenant_members(current_user.current_tenant)        return {'result': 'success', 'accounts': members}, 200class MemberInviteEmailApi(Resource):    """Invite a new member by email."""    @setup_required    @login_required    @account_initialization_required    def post(self):        parser = reqparse.RequestParser()        parser.add_argument('email', type=str, required=True, location='json')        parser.add_argument('role', type=str, required=True, default='admin', location='json')        args = parser.parse_args()        invitee_email = args['email']        invitee_role = args['role']        if invitee_role not in ['admin', 'normal']:            return {'code': 'invalid-role', 'message': 'Invalid role'}, 400        inviter = current_user        try:            token = RegisterService.invite_new_member(inviter.current_tenant, invitee_email, role=invitee_role,                                                      inviter=inviter)            account = db.session.query(Account, TenantAccountJoin.role).join(                TenantAccountJoin, Account.id == TenantAccountJoin.account_id            ).filter(Account.email == args['email']).first()            account, role = account            account = marshal(account, account_fields)            account['role'] = role        except services.errors.account.CannotOperateSelfError as e:            return {'code': 'cannot-operate-self', 'message': str(e)}, 400        except services.errors.account.NoPermissionError as e:            return {'code': 'forbidden', 'message': str(e)}, 403        except services.errors.account.AccountAlreadyInTenantError as e:            return {'code': 'email-taken', 'message': str(e)}, 409        except Exception as e:            return {'code': 'unexpected-error', 'message': str(e)}, 500        # todo:413        return {            'result': 'success',            'account': account,            'invite_url': '{}/activate?workspace_id={}&email={}&token={}'.format(                current_app.config.get("CONSOLE_WEB_URL"),                str(current_user.current_tenant_id),                invitee_email,                token            )        }, 201class MemberCancelInviteApi(Resource):    """Cancel an invitation by member id."""    @setup_required    @login_required    @account_initialization_required    def delete(self, member_id):        member = db.session.query(Account).filter(Account.id == str(member_id)).first()        if not member:            abort(404)        try:            TenantService.remove_member_from_tenant(current_user.current_tenant, member, current_user)        except services.errors.account.CannotOperateSelfError as e:            return {'code': 'cannot-operate-self', 'message': str(e)}, 400        except services.errors.account.NoPermissionError as e:            return {'code': 'forbidden', 'message': str(e)}, 403        except services.errors.account.MemberNotInTenantError as e:            return {'code': 'member-not-found', 'message': str(e)}, 404        except Exception as e:            raise ValueError(str(e))        return {'result': 'success'}, 204class MemberUpdateRoleApi(Resource):    """Update member role."""    @setup_required    @login_required    @account_initialization_required    def put(self, member_id):        parser = reqparse.RequestParser()        parser.add_argument('role', type=str, required=True, location='json')        args = parser.parse_args()        new_role = args['role']        if new_role not in ['admin', 'normal', 'owner']:            return {'code': 'invalid-role', 'message': 'Invalid role'}, 400        member = Account.query.get(str(member_id))        if not member:            abort(404)        try:            TenantService.update_member_role(current_user.current_tenant, member, new_role, current_user)        except Exception as e:            raise ValueError(str(e))        # todo: 403        return {'result': 'success'}api.add_resource(MemberListApi, '/workspaces/current/members')api.add_resource(MemberInviteEmailApi, '/workspaces/current/members/invite-email')api.add_resource(MemberCancelInviteApi, '/workspaces/current/members/<uuid:member_id>')api.add_resource(MemberUpdateRoleApi, '/workspaces/current/members/<uuid:member_id>/update-role')
 |