<commit_before>
import ujson

from tornado.gen import coroutine, Return
from tornado.web import HTTPError

from common import to_int
from common.internal import InternalError
from common.social import APIError, AuthResponse
from common.handler import AuthenticatedHandler
from common.access import scoped, AccessToken, parse_scopes
from common.validate import validate_value, ValidationError

from model.request import RequestError, RequestType, NoSuchRequest
from model.connection import ConnectionError, ConnectionsModel
from model.social import SocialNotFound, NoFriendsFound, SocialAuthenticationRequired
from model.group import GroupError, GroupsModel, GroupFlags, NoSuchGroup, NoSuchParticipation, GroupJoinMethod


class ConnectionsHandler(AuthenticatedHandler):
    @scoped()
    @coroutine
    def get(self):
        profile_fields = filter(
            bool, 
            self.get_argument("profile_fields", "").split(","))

        try:
            connections = yield self.application.connections.get_connections_profiles(
                self.token.get(AccessToken.GAMESPACE),
                self.token.account,
                profile_fields)
            
        except ConnectionError as e:
            raise HTTPError(e.code, e.message)

        self.dumps(connections)


class AccountConnectionHandler(AuthenticatedHandler):
    @scoped()
    @coroutine
    def delete(self, target_account):

        gamespace = self.token.get(AccessToken.GAMESPACE)

        notify_str = self.get_argument("notify", None)
        if notify_str:
            try:
                notify = ujson.loads(notify_str)
            except (KeyError, ValueError):
                raise HTTPError(400, "Notify is corrupted")
        else:
            notify = None

        try:
            yield self.application.connections.delete(
                gamespace, self.token.account, target_account, notify=notify)

        except ConnectionError as e:
            raise HTTPError(e.code, e.message)

    def options(self):
        self.set_header("Access-Control-Allow-Methods", "POST,DELETE,OPTIONS")

    @scoped()
    @coroutine
    def post(self, target_account):

        approval = self.get_argument("approval", "true") == "true"
        gamespace = self.token.get(AccessToken.GAMESPACE)

        notify_str = self.get_argument("notify", None)
        if notify_str:
            try:
                notify = ujson.loads(notify_str)
            except (KeyError, ValueError):
                raise HTTPError(400, "Notify is corrupted")
        else:
            notify = None

        if not approval and not self.token.has_scope(ConnectionsModel.APPROVAL_SCOPE):
            raise HTTPError(403, "Scope '{0}' is required if approval is disabled".format(
                ConnectionsModel.APPROVAL_SCOPE))

        try:
            result = yield self.application.connections.request_connection(
                gamespace, self.token.account, target_account, approval=approval, notify=notify)
        except ConnectionError as e:
            raise HTTPError(e.code, e.message)

        if result:
            self.dumps(result)


class ApproveConnectionHandler(AuthenticatedHandler):
    @scoped()
    @coroutine
    def post(self, approve_account_id):
        key = self.get_argument("key")
        gamespace = self.token.get(AccessToken.GAMESPACE)
        account_id = self.token.account

        notify_str = self.get_argument("notify", None)
        if notify_str:
            try:
                notify = ujson.loads(notify_str)
            except (KeyError, ValueError):
                raise HTTPError(400, "Notify is corrupted")
        else:
            notify = None

        try:
            yield self.application.connections.approve_connection(
                gamespace, account_id, approve_account_id, key, notify=notify)
        except ConnectionError as e:
            raise HTTPError(e.code, e.message)


class RejectConnectionHandler(AuthenticatedHandler):
    @scoped()
    @coroutine
    def post(self, reject_account_id):

        key = self.get_argument("key")
        gamespace = self.token.get(AccessToken.GAMESPACE)
        account_id = self.token.account

        notify_str = self.get_argument("notify", None)
        if notify_str:
            try:
                notify = ujson.loads(notify_str)
            except (KeyError, ValueError):
                raise HTTPError(400, "Notify is corrupted")
        else:
            notify = None

        try:
            yield self.application.connections.reject_connection(
                gamespace, account_id, reject_account_id, key, notify=notify)
        except ConnectionError as e:
            raise HTTPError(500, e.message)


class ExternalConnectionsHandler(AuthenticatedHandler):
    @scoped()
    @coroutine
    def get(self):
        try:
            friends = yield self.application.social.list_friends(
                self.token.get(AccessToken.GAMESPACE),
                self.token.account)

        except SocialAuthenticationRequired as e:
            raise HTTPError(401, ujson.dumps({
                "credential": e.credential,
                "username": e.username
            }))

        except NoFriendsFound:
            raise HTTPError(404, "No connections found")

        except APIError as e:
            raise HTTPError(e.code, e.body)

        self.dumps(friends)


class InternalHandler(object):
    def __init__(self, application):
        self.application = application

    @coroutine
    def attach_account(self, gamespace, credential, username, account, env=None):
        yield self.application.tokens.attach(
            gamespace,
            credential,
            username,
            account)

        try:
            api = self.application.social.api(credential)
        except SocialNotFound:
            raise InternalError(404, "No such credential: '{0}'.".format(credential))

        try:
            result = yield api.get_social_profile(gamespace, username, account, env=env)
        except APIError as e:
            raise InternalError(e.code, e.message)
        else:
            raise Return(result)

    @coroutine
    def import_social(self, gamespace, username, credential, auth):

        if not isinstance(auth, dict):
            raise InternalError(400, "Auth should be a dict")

        auth = AuthResponse(**auth)

        social = self.application.social
        try:
            api = social.api(credential)
        except SocialNotFound:
            raise InternalError(404, "No such credential: '{0}'.".format(credential))

        try:
            result = yield api.import_social(
                gamespace,
                username,
                auth)

        except APIError as e:
            raise HTTPError(e.code, e.message)
        else:
            raise Return(result)

    @coroutine
    def get_connections(self, gamespace, account_id, profile_fields):

        connections_data = self.application.connections

        try:
            connections = yield connections_data.get_connections_profiles(
                gamespace,
                account_id,
                profile_fields)

        except ConnectionError as e:
            raise HTTPError(e.code, e.message)

        raise Return(connections)


class CreateGroupHandler(AuthenticatedHandler):
    @scoped(scopes=["group_create"])
    @coroutine
    def post(self):

        join_method_str = self.get_argument("join_method", GroupJoinMethod.FREE)
        max_members = self.get_argument("max_members", GroupsModel.DEFAULT_MAX_MEMBERS)

        if join_method_str not in GroupJoinMethod:
            raise HTTPError(400, "Invalid join method")

        join_method = GroupJoinMethod(join_method_str)

        try:
            group_profile = ujson.loads(self.get_argument("group_profile", "{}"))
        except (KeyError, ValueError):
            raise HTTPError(400, "Profile is corrupted")

        try:
            participation_profile = ujson.loads(self.get_argument("participation_profile", "{}"))
        except (KeyError, ValueError):
            raise HTTPError(400, "Profile is corrupted")

        group_messages = self.get_argument("group_messages", "true") == "true"

        flags = GroupFlags()

        if group_messages:
            flags.set(GroupFlags.MESSAGE_SUPPORT)

        gamespace = self.token.get(AccessToken.GAMESPACE)
        account = self.token.account

        try:
            group_id = yield self.application.groups.create_group(
                gamespace, group_profile, flags, join_method, max_members,
                account, participation_profile)
        except GroupError as e:
            raise HTTPError(e.code, e.message)

        self.dumps({
            "id": group_id
        })


class GroupHandler(AuthenticatedHandler):
    @scoped(scopes=["group"])
    @coroutine
    def get(self, group_id):

        gamespace = self.token.get(AccessToken.GAMESPACE)
        account_id = self.token.account

        try:
            group, participants, my_participation = yield self.application.groups.get_group_with_participants(
                gamespace, group_id, account_id)
        except NoSuchGroup as e:
            raise HTTPError(404, "No such group")
        except GroupError as e:
            raise HTTPError(e.code, e.message)

        result = {
            "group": {
                "profile": group.profile,
                "join_method": str(group.join_method),
                "free_members": group.free_members,
                "owner": str(group.owner)
            },
            "participants": {
                participant.account: {
                    "role": participant.role,
                    "permissions": participant.permissions,
                    "profile": participant.profile
                }
                for participant in participants
            }
        }

        if my_participation:
            result["me"] = {
                "role": my_participation.role,
                "permissions": my_participation.permissions,
                "profile": my_participation.profile
            }

            if GroupFlags.MESSAGE_SUPPORT in group.flags:
                result["message"] = {
                    "recipient_class": my_participation.message_recipient_class,
                    "recipient": my_participation.message_recipient,
                }

        self.dumps(result)

    @scoped(scopes=["group", "group_write"])
    @coroutine
    def post(self, group_id):

        try:
            group_profile = ujson.loads(self.get_argument("profile"))
        except (KeyError, ValueError):
            raise HTTPError(400, "Profile is corrupted")

        notify_str = self.get_argument("notify", None)
        if notify_str:
            try:
                notify = ujson.loads(notify_str)
            except (KeyError, ValueError):
                raise HTTPError(400, "Notify is corrupted")
        else:
            notify = None

        merge = self.get_argument("merge", "true") == "true"
        gamespace = self.token.get(AccessToken.GAMESPACE)
        account = self.token.account

        try:
            result = yield self.application.groups.update_group(
                gamespace, group_id, account, group_profile, merge=merge, notify=notify)
        except GroupError as e:
            raise HTTPError(e.code, e.message)

        self.dumps({
            "group": {
                "profile": result
            }
        })


class GroupJoinHandler(AuthenticatedHandler):
    @scoped(scopes=["group"])
    @coroutine
    def post(self, group_id):

        gamespace = self.token.get(AccessToken.GAMESPACE)
        account = self.token.account
        key = self.get_argument("key", None)

        try:
            participation_profile = ujson.loads(self.get_argument("participation_profile", "{}"))
        except (KeyError, ValueError):
            raise HTTPError(400, "Profile is corrupted")

        notify_str = self.get_argument("notify", None)
        if notify_str:
            try:
                notify = ujson.loads(notify_str)
            except (KeyError, ValueError):
                raise HTTPError(400, "Notify is corrupted")
        else:
            notify = None

        try:
            yield self.application.groups.join_group(
                gamespace, group_id, account,
                participation_profile, key=key, notify=notify)
        except NoSuchGroup:
            raise HTTPError(404, "No such group")
        except GroupError as e:
            raise HTTPError(e.code, e.message)


class GroupLeaveHandler(AuthenticatedHandler):
    @scoped(scopes=["group"])
    @coroutine
    def post(self, group_id):

        gamespace = self.token.get(AccessToken.GAMESPACE)
        account = self.token.account

        notify_str = self.get_argument("notify", None)
        if notify_str:
            try:
                notify = ujson.loads(notify_str)
            except (KeyError, ValueError):
                raise HTTPError(400, "Notify is corrupted")
        else:
            notify = None

        try:
            yield self.application.groups.leave_group(
                gamespace, group_id, account, notify=notify)
        except NoSuchGroup:
            raise HTTPError(404, "No such group")
        except GroupError as e:
            raise HTTPError(e.code, e.message)


class GroupOwnershipHandler(AuthenticatedHandler):
    @scoped(scopes=["group"])
    @coroutine
    def post(self, group_id):

        account_transfer_to = self.get_argument("account_transfer_to")

        gamespace = self.token.get(AccessToken.GAMESPACE)
        account = self.token.account

        notify_str = self.get_argument("notify", None)
        if notify_str:
            try:
                notify = ujson.loads(notify_str)
            except (KeyError, ValueError):
                raise HTTPError(400, "Notify is corrupted")
        else:
            notify = None

        try:
            yield self.application.groups.transfer_ownership(
                gamespace, group_id, account, account_transfer_to, notify=notify)
        except NoSuchGroup:
            raise HTTPError(404, "No such group")
        except GroupError as e:
            raise HTTPError(e.code, e.message)


class GroupRequestJoinHandler(AuthenticatedHandler):
    @scoped(scopes=["group"])
    @coroutine
    def post(self, group_id):

        gamespace = self.token.get(AccessToken.GAMESPACE)
        account = self.token.account

        try:
            participation_profile = ujson.loads(self.get_argument("participation_profile", "{}"))
        except (KeyError, ValueError):
            raise HTTPError(400, "Profile is corrupted")

        notify_str = self.get_argument("notify", None)
        if notify_str:
            try:
                notify = ujson.loads(notify_str)
            except (KeyError, ValueError):
                raise HTTPError(400, "Notify is corrupted")
        else:
            notify = None

        try:
            key = yield self.application.groups.join_group_request(
                gamespace, group_id, account, participation_profile, notify=notify)
        except NoSuchGroup:
            raise HTTPError(404, "No such group")
        except GroupError as e:
            raise HTTPError(e.code, e.message)

        self.dumps({
            "key": key
        })


class GroupInviteJoinHandler(AuthenticatedHandler):
    @scoped(scopes=["group"])
    @coroutine
    def post(self, group_id, invite_account):

        gamespace_id = self.token.get(AccessToken.GAMESPACE)
        account_id = self.token.account
        role = self.get_argument("role")

        try:
            permissions = ujson.loads(self.get_argument("permissions"))
        except (KeyError, ValueError):
            raise HTTPError(400, "Permissions json is corrupted")

        notify_str = self.get_argument("notify", None)
        if notify_str:
            try:
                notify = ujson.loads(notify_str)
            except (KeyError, ValueError):
                raise HTTPError(400, "Notify is corrupted")
        else:
            notify = None

        try:
            key = yield self.application.groups.invite_to_group(
                gamespace_id, group_id, account_id, invite_account,
                role, permissions, notify=notify)
        except NoSuchGroup:
            raise HTTPError(404, "No such group")
        except NoSuchParticipation:
            raise HTTPError(406, "You are not a member of this group")
        except GroupError as e:
            raise HTTPError(e.code, e.message)

        self.dumps({
            "key": key
        })


class GroupApproveJoinHandler(AuthenticatedHandler):
    @scoped(scopes=["group"])
    @coroutine
    def post(self, group_id, approve_account):

        gamespace_id = self.token.get(AccessToken.GAMESPACE)
        account_id = self.token.account

        role = to_int(self.get_argument("role"))
        key = self.get_argument("key")

        try:
            permissions = ujson.loads(self.get_argument("permissions"))
        except (KeyError, ValueError):
            raise HTTPError(400, "Permissions json is corrupted")

        notify_str = self.get_argument("notify", None)
        if notify_str:
            try:
                notify = ujson.loads(notify_str)
            except (KeyError, ValueError):
                raise HTTPError(400, "Notify is corrupted")
        else:
            notify = None

        try:
            yield self.application.groups.approve_join_group(
                gamespace_id, group_id, account_id, approve_account,
                role, key, permissions, notify=notify)
        except NoSuchGroup:
            raise HTTPError(404, "No such group")
        except NoSuchParticipation:
            raise HTTPError(406, "You are not a member of this group")
        except GroupError as e:
            raise HTTPError(e.code, e.message)


class GroupParticipationHandler(AuthenticatedHandler):
    @scoped(scopes=["group"])
    @coroutine
    def get(self, group_id, account_id):

        gamespace = self.token.get(AccessToken.GAMESPACE)

        if account_id == "me":
            account_id = self.token.account

        try:
            participation = yield self.application.groups.get_group_participation(
                gamespace, group_id, account_id)
        except NoSuchParticipation as e:
            raise HTTPError(404, "Player is not participating this group")
        except GroupError as e:
            raise HTTPError(e.code, e.message)

        self.dumps({
            "participation": {
                "profile": participation.profile,
                "role": participation.role,
                "permissions": participation.permissions
            }
        })

    @scoped(scopes=["group"])
    @coroutine
    def post(self, group_id, account_id):

        if account_id == "me":
            account_id = self.token.account
        else:
            account_id = to_int(account_id)

        try:
            participation_profile = ujson.loads(self.get_argument("profile"))
        except (KeyError, ValueError):
            raise HTTPError(400, "Profile is corrupted")

        gamespace = self.token.get(AccessToken.GAMESPACE)
        my_account = self.token.account

        notify_str = self.get_argument("notify", None)
        if notify_str:
            try:
                notify = ujson.loads(notify_str)
            except (KeyError, ValueError):
                raise HTTPError(400, "Notify is corrupted")
        else:
            notify = None

        try:
            result = yield self.application.groups.update_group_participation(
                gamespace, group_id, my_account, account_id, participation_profile, notify=notify)
        except NoSuchParticipation:
            raise HTTPError(404, "Player is not participating this group")
        except GroupError as e:
            raise HTTPError(e.code, e.message)
        else:
            self.dumps({
                "profile": result
            })

    @scoped(scopes=["group"])
    @coroutine
    def delete(self, group_id, account_id):

        gamespace = self.token.get(AccessToken.GAMESPACE)
        my_account = self.token.account

        try:
            yield self.application.groups.kick_from_group(
                gamespace, group_id, my_account, account_id)
        except NoSuchParticipation:
            raise HTTPError(404, "Player is not participating this group")
        except GroupError as e:
            raise HTTPError(e.code, e.message)
<commit_msg>Missed merge argument for one of requests<commit_after>
import ujson

from tornado.gen import coroutine, Return
from tornado.web import HTTPError

from common import to_int
from common.internal import InternalError
from common.social import APIError, AuthResponse
from common.handler import AuthenticatedHandler
from common.access import scoped, AccessToken, parse_scopes
from common.validate import validate_value, ValidationError

from model.request import RequestError, RequestType, NoSuchRequest
from model.connection import ConnectionError, ConnectionsModel
from model.social import SocialNotFound, NoFriendsFound, SocialAuthenticationRequired
from model.group import GroupError, GroupsModel, GroupFlags, NoSuchGroup, NoSuchParticipation, GroupJoinMethod


class ConnectionsHandler(AuthenticatedHandler):
    @scoped()
    @coroutine
    def get(self):
        profile_fields = filter(
            bool, 
            self.get_argument("profile_fields", "").split(","))

        try:
            connections = yield self.application.connections.get_connections_profiles(
                self.token.get(AccessToken.GAMESPACE),
                self.token.account,
                profile_fields)
            
        except ConnectionError as e:
            raise HTTPError(e.code, e.message)

        self.dumps(connections)


class AccountConnectionHandler(AuthenticatedHandler):
    @scoped()
    @coroutine
    def delete(self, target_account):

        gamespace = self.token.get(AccessToken.GAMESPACE)

        notify_str = self.get_argument("notify", None)
        if notify_str:
            try:
                notify = ujson.loads(notify_str)
            except (KeyError, ValueError):
                raise HTTPError(400, "Notify is corrupted")
        else:
            notify = None

        try:
            yield self.application.connections.delete(
                gamespace, self.token.account, target_account, notify=notify)

        except ConnectionError as e:
            raise HTTPError(e.code, e.message)

    def options(self):
        self.set_header("Access-Control-Allow-Methods", "POST,DELETE,OPTIONS")

    @scoped()
    @coroutine
    def post(self, target_account):

        approval = self.get_argument("approval", "true") == "true"
        gamespace = self.token.get(AccessToken.GAMESPACE)

        notify_str = self.get_argument("notify", None)
        if notify_str:
            try:
                notify = ujson.loads(notify_str)
            except (KeyError, ValueError):
                raise HTTPError(400, "Notify is corrupted")
        else:
            notify = None

        if not approval and not self.token.has_scope(ConnectionsModel.APPROVAL_SCOPE):
            raise HTTPError(403, "Scope '{0}' is required if approval is disabled".format(
                ConnectionsModel.APPROVAL_SCOPE))

        try:
            result = yield self.application.connections.request_connection(
                gamespace, self.token.account, target_account, approval=approval, notify=notify)
        except ConnectionError as e:
            raise HTTPError(e.code, e.message)

        if result:
            self.dumps(result)


class ApproveConnectionHandler(AuthenticatedHandler):
    @scoped()
    @coroutine
    def post(self, approve_account_id):
        key = self.get_argument("key")
        gamespace = self.token.get(AccessToken.GAMESPACE)
        account_id = self.token.account

        notify_str = self.get_argument("notify", None)
        if notify_str:
            try:
                notify = ujson.loads(notify_str)
            except (KeyError, ValueError):
                raise HTTPError(400, "Notify is corrupted")
        else:
            notify = None

        try:
            yield self.application.connections.approve_connection(
                gamespace, account_id, approve_account_id, key, notify=notify)
        except ConnectionError as e:
            raise HTTPError(e.code, e.message)


class RejectConnectionHandler(AuthenticatedHandler):
    @scoped()
    @coroutine
    def post(self, reject_account_id):

        key = self.get_argument("key")
        gamespace = self.token.get(AccessToken.GAMESPACE)
        account_id = self.token.account

        notify_str = self.get_argument("notify", None)
        if notify_str:
            try:
                notify = ujson.loads(notify_str)
            except (KeyError, ValueError):
                raise HTTPError(400, "Notify is corrupted")
        else:
            notify = None

        try:
            yield self.application.connections.reject_connection(
                gamespace, account_id, reject_account_id, key, notify=notify)
        except ConnectionError as e:
            raise HTTPError(500, e.message)


class ExternalConnectionsHandler(AuthenticatedHandler):
    @scoped()
    @coroutine
    def get(self):
        try:
            friends = yield self.application.social.list_friends(
                self.token.get(AccessToken.GAMESPACE),
                self.token.account)

        except SocialAuthenticationRequired as e:
            raise HTTPError(401, ujson.dumps({
                "credential": e.credential,
                "username": e.username
            }))

        except NoFriendsFound:
            raise HTTPError(404, "No connections found")

        except APIError as e:
            raise HTTPError(e.code, e.body)

        self.dumps(friends)


class InternalHandler(object):
    def __init__(self, application):
        self.application = application

    @coroutine
    def attach_account(self, gamespace, credential, username, account, env=None):
        yield self.application.tokens.attach(
            gamespace,
            credential,
            username,
            account)

        try:
            api = self.application.social.api(credential)
        except SocialNotFound:
            raise InternalError(404, "No such credential: '{0}'.".format(credential))

        try:
            result = yield api.get_social_profile(gamespace, username, account, env=env)
        except APIError as e:
            raise InternalError(e.code, e.message)
        else:
            raise Return(result)

    @coroutine
    def import_social(self, gamespace, username, credential, auth):

        if not isinstance(auth, dict):
            raise InternalError(400, "Auth should be a dict")

        auth = AuthResponse(**auth)

        social = self.application.social
        try:
            api = social.api(credential)
        except SocialNotFound:
            raise InternalError(404, "No such credential: '{0}'.".format(credential))

        try:
            result = yield api.import_social(
                gamespace,
                username,
                auth)

        except APIError as e:
            raise HTTPError(e.code, e.message)
        else:
            raise Return(result)

    @coroutine
    def get_connections(self, gamespace, account_id, profile_fields):

        connections_data = self.application.connections

        try:
            connections = yield connections_data.get_connections_profiles(
                gamespace,
                account_id,
                profile_fields)

        except ConnectionError as e:
            raise HTTPError(e.code, e.message)

        raise Return(connections)


class CreateGroupHandler(AuthenticatedHandler):
    @scoped(scopes=["group_create"])
    @coroutine
    def post(self):

        join_method_str = self.get_argument("join_method", GroupJoinMethod.FREE)
        max_members = self.get_argument("max_members", GroupsModel.DEFAULT_MAX_MEMBERS)

        if join_method_str not in GroupJoinMethod:
            raise HTTPError(400, "Invalid join method")

        join_method = GroupJoinMethod(join_method_str)

        try:
            group_profile = ujson.loads(self.get_argument("group_profile", "{}"))
        except (KeyError, ValueError):
            raise HTTPError(400, "Profile is corrupted")

        try:
            participation_profile = ujson.loads(self.get_argument("participation_profile", "{}"))
        except (KeyError, ValueError):
            raise HTTPError(400, "Profile is corrupted")

        group_messages = self.get_argument("group_messages", "true") == "true"

        flags = GroupFlags()

        if group_messages:
            flags.set(GroupFlags.MESSAGE_SUPPORT)

        gamespace = self.token.get(AccessToken.GAMESPACE)
        account = self.token.account

        try:
            group_id = yield self.application.groups.create_group(
                gamespace, group_profile, flags, join_method, max_members,
                account, participation_profile)
        except GroupError as e:
            raise HTTPError(e.code, e.message)

        self.dumps({
            "id": group_id
        })


class GroupHandler(AuthenticatedHandler):
    @scoped(scopes=["group"])
    @coroutine
    def get(self, group_id):

        gamespace = self.token.get(AccessToken.GAMESPACE)
        account_id = self.token.account

        try:
            group, participants, my_participation = yield self.application.groups.get_group_with_participants(
                gamespace, group_id, account_id)
        except NoSuchGroup as e:
            raise HTTPError(404, "No such group")
        except GroupError as e:
            raise HTTPError(e.code, e.message)

        result = {
            "group": {
                "profile": group.profile,
                "join_method": str(group.join_method),
                "free_members": group.free_members,
                "owner": str(group.owner)
            },
            "participants": {
                participant.account: {
                    "role": participant.role,
                    "permissions": participant.permissions,
                    "profile": participant.profile
                }
                for participant in participants
            }
        }

        if my_participation:
            result["me"] = {
                "role": my_participation.role,
                "permissions": my_participation.permissions,
                "profile": my_participation.profile
            }

            if GroupFlags.MESSAGE_SUPPORT in group.flags:
                result["message"] = {
                    "recipient_class": my_participation.message_recipient_class,
                    "recipient": my_participation.message_recipient,
                }

        self.dumps(result)

    @scoped(scopes=["group", "group_write"])
    @coroutine
    def post(self, group_id):

        try:
            group_profile = ujson.loads(self.get_argument("profile"))
        except (KeyError, ValueError):
            raise HTTPError(400, "Profile is corrupted")

        notify_str = self.get_argument("notify", None)
        if notify_str:
            try:
                notify = ujson.loads(notify_str)
            except (KeyError, ValueError):
                raise HTTPError(400, "Notify is corrupted")
        else:
            notify = None

        merge = self.get_argument("merge", "true") == "true"
        gamespace = self.token.get(AccessToken.GAMESPACE)
        account = self.token.account

        try:
            result = yield self.application.groups.update_group(
                gamespace, group_id, account, group_profile, merge=merge, notify=notify)
        except GroupError as e:
            raise HTTPError(e.code, e.message)

        self.dumps({
            "group": {
                "profile": result
            }
        })


class GroupJoinHandler(AuthenticatedHandler):
    @scoped(scopes=["group"])
    @coroutine
    def post(self, group_id):

        gamespace = self.token.get(AccessToken.GAMESPACE)
        account = self.token.account
        key = self.get_argument("key", None)

        try:
            participation_profile = ujson.loads(self.get_argument("participation_profile", "{}"))
        except (KeyError, ValueError):
            raise HTTPError(400, "Profile is corrupted")

        notify_str = self.get_argument("notify", None)
        if notify_str:
            try:
                notify = ujson.loads(notify_str)
            except (KeyError, ValueError):
                raise HTTPError(400, "Notify is corrupted")
        else:
            notify = None

        try:
            yield self.application.groups.join_group(
                gamespace, group_id, account,
                participation_profile, key=key, notify=notify)
        except NoSuchGroup:
            raise HTTPError(404, "No such group")
        except GroupError as e:
            raise HTTPError(e.code, e.message)


class GroupLeaveHandler(AuthenticatedHandler):
    @scoped(scopes=["group"])
    @coroutine
    def post(self, group_id):

        gamespace = self.token.get(AccessToken.GAMESPACE)
        account = self.token.account

        notify_str = self.get_argument("notify", None)
        if notify_str:
            try:
                notify = ujson.loads(notify_str)
            except (KeyError, ValueError):
                raise HTTPError(400, "Notify is corrupted")
        else:
            notify = None

        try:
            yield self.application.groups.leave_group(
                gamespace, group_id, account, notify=notify)
        except NoSuchGroup:
            raise HTTPError(404, "No such group")
        except GroupError as e:
            raise HTTPError(e.code, e.message)


class GroupOwnershipHandler(AuthenticatedHandler):
    @scoped(scopes=["group"])
    @coroutine
    def post(self, group_id):

        account_transfer_to = self.get_argument("account_transfer_to")

        gamespace = self.token.get(AccessToken.GAMESPACE)
        account = self.token.account

        notify_str = self.get_argument("notify", None)
        if notify_str:
            try:
                notify = ujson.loads(notify_str)
            except (KeyError, ValueError):
                raise HTTPError(400, "Notify is corrupted")
        else:
            notify = None

        try:
            yield self.application.groups.transfer_ownership(
                gamespace, group_id, account, account_transfer_to, notify=notify)
        except NoSuchGroup:
            raise HTTPError(404, "No such group")
        except GroupError as e:
            raise HTTPError(e.code, e.message)


class GroupRequestJoinHandler(AuthenticatedHandler):
    @scoped(scopes=["group"])
    @coroutine
    def post(self, group_id):

        gamespace = self.token.get(AccessToken.GAMESPACE)
        account = self.token.account

        try:
            participation_profile = ujson.loads(self.get_argument("participation_profile", "{}"))
        except (KeyError, ValueError):
            raise HTTPError(400, "Profile is corrupted")

        notify_str = self.get_argument("notify", None)
        if notify_str:
            try:
                notify = ujson.loads(notify_str)
            except (KeyError, ValueError):
                raise HTTPError(400, "Notify is corrupted")
        else:
            notify = None

        try:
            key = yield self.application.groups.join_group_request(
                gamespace, group_id, account, participation_profile, notify=notify)
        except NoSuchGroup:
            raise HTTPError(404, "No such group")
        except GroupError as e:
            raise HTTPError(e.code, e.message)

        self.dumps({
            "key": key
        })


class GroupInviteJoinHandler(AuthenticatedHandler):
    @scoped(scopes=["group"])
    @coroutine
    def post(self, group_id, invite_account):

        gamespace_id = self.token.get(AccessToken.GAMESPACE)
        account_id = self.token.account
        role = self.get_argument("role")

        try:
            permissions = ujson.loads(self.get_argument("permissions"))
        except (KeyError, ValueError):
            raise HTTPError(400, "Permissions json is corrupted")

        notify_str = self.get_argument("notify", None)
        if notify_str:
            try:
                notify = ujson.loads(notify_str)
            except (KeyError, ValueError):
                raise HTTPError(400, "Notify is corrupted")
        else:
            notify = None

        try:
            key = yield self.application.groups.invite_to_group(
                gamespace_id, group_id, account_id, invite_account,
                role, permissions, notify=notify)
        except NoSuchGroup:
            raise HTTPError(404, "No such group")
        except NoSuchParticipation:
            raise HTTPError(406, "You are not a member of this group")
        except GroupError as e:
            raise HTTPError(e.code, e.message)

        self.dumps({
            "key": key
        })


class GroupApproveJoinHandler(AuthenticatedHandler):
    @scoped(scopes=["group"])
    @coroutine
    def post(self, group_id, approve_account):

        gamespace_id = self.token.get(AccessToken.GAMESPACE)
        account_id = self.token.account

        role = to_int(self.get_argument("role"))
        key = self.get_argument("key")

        try:
            permissions = ujson.loads(self.get_argument("permissions"))
        except (KeyError, ValueError):
            raise HTTPError(400, "Permissions json is corrupted")

        notify_str = self.get_argument("notify", None)
        if notify_str:
            try:
                notify = ujson.loads(notify_str)
            except (KeyError, ValueError):
                raise HTTPError(400, "Notify is corrupted")
        else:
            notify = None

        try:
            yield self.application.groups.approve_join_group(
                gamespace_id, group_id, account_id, approve_account,
                role, key, permissions, notify=notify)
        except NoSuchGroup:
            raise HTTPError(404, "No such group")
        except NoSuchParticipation:
            raise HTTPError(406, "You are not a member of this group")
        except GroupError as e:
            raise HTTPError(e.code, e.message)


class GroupParticipationHandler(AuthenticatedHandler):
    @scoped(scopes=["group"])
    @coroutine
    def get(self, group_id, account_id):

        gamespace = self.token.get(AccessToken.GAMESPACE)

        if account_id == "me":
            account_id = self.token.account

        try:
            participation = yield self.application.groups.get_group_participation(
                gamespace, group_id, account_id)
        except NoSuchParticipation as e:
            raise HTTPError(404, "Player is not participating this group")
        except GroupError as e:
            raise HTTPError(e.code, e.message)

        self.dumps({
            "participation": {
                "profile": participation.profile,
                "role": participation.role,
                "permissions": participation.permissions
            }
        })

    @scoped(scopes=["group"])
    @coroutine
    def post(self, group_id, account_id):

        if account_id == "me":
            account_id = self.token.account
        else:
            account_id = to_int(account_id)

        try:
            participation_profile = ujson.loads(self.get_argument("profile"))
        except (KeyError, ValueError):
            raise HTTPError(400, "Profile is corrupted")

        gamespace = self.token.get(AccessToken.GAMESPACE)
        my_account = self.token.account

        notify_str = self.get_argument("notify", None)
        if notify_str:
            try:
                notify = ujson.loads(notify_str)
            except (KeyError, ValueError):
                raise HTTPError(400, "Notify is corrupted")
        else:
            notify = None

        merge = self.get_argument("merge", "true") == "true"

        try:
            result = yield self.application.groups.update_group_participation(
                gamespace, group_id, my_account, account_id, participation_profile, merge=merge, notify=notify)
        except NoSuchParticipation:
            raise HTTPError(404, "Player is not participating this group")
        except GroupError as e:
            raise HTTPError(e.code, e.message)
        else:
            self.dumps({
                "profile": result
            })

    @scoped(scopes=["group"])
    @coroutine
    def delete(self, group_id, account_id):

        gamespace = self.token.get(AccessToken.GAMESPACE)
        my_account = self.token.account

        try:
            yield self.application.groups.kick_from_group(
                gamespace, group_id, my_account, account_id)
        except NoSuchParticipation:
            raise HTTPError(404, "Player is not participating this group")
        except GroupError as e:
            raise HTTPError(e.code, e.message)

{'fraction_non_alphanumeric': 0.08886678473519494, 'fraction_numerical': 0.005968121497367719, 'mean_word_length': 2.0871779508687838, 'pattern_counts': {'":': 56, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6836532', 'n_tokens_mistral': 11378, 'n_tokens_neox': 11096, 'n_words': 2513}