/**
 * @file Implémentation des requêtes GraphQL.
 * @author akka vodol, ofacklam
 * @memberof GraphQL
*/

import { AuthenticationError } from "apollo-server-core";
import { Context } from "./typeDefs/queries";
import { User } from "./resolvers/users";
import { Group, SimpleGroup, MetaGroup } from "./resolvers/groups";
import { Announcement, Event, PrivatePost, Question, Answer, Message } from "./resolvers/messages";
import { UserJoinGroup, GroupJoinMetagroup, GroupCoauthorEvent, Request } from "./resolvers/requests";
import { GroupCollection, GroupSet } from "./connectors/tools";

/*
    Le tag @rights est la gestion des autorisations.

    Le système GraphQL est pensé comme l'interface par laquelle les utilisateurs
    intéragissent avec sigma, les graphismes en moins.
    Le client peut envoyer tout type de requête. C'est au niveau des resolvers
    que les permissions sont gérées. D'où le @rights

    Commençons par un rappel sur le fonctionnement des droits.
    Chaque utilisateur a un certain niveau de droit sur chaque groupe. Ce niveau de droit indique
    ce qu'il a le droit de savoir et de faire. Chaque niveau est inclus dans les niveaus supérieur.
    Les différents niveaux sont :
    none - aucun droit
    viewer : l'utilisateur a visibilité sur le groupe. Il sait que le groupe existe, et a accès à un certain nombre d'infos.
    member : l'utilisateur est membre du groupe
    speaker : l'utilisateur peut parler au nom du groupe. Il a le droit de publier des annonces et d'organiser des évènements
    admin : l'utilisateur a tous les droits sur le groupe

    Certaines fonctions de connectors effectuent des vérifications d'authorisations avant
    de renvoyer une réponse, d'autres non. Pour être sur qu'on ne renvoie jamais de réponse
    sans avoir au préalable éffectué les bonnes vérifications, chaque fonction possède dans sa
    description un attribut droit, qui décrit les droits que fournit cette fonction.

    La valeur de @rights peut être :
    super - la fonction n'effectue aucune véri-fication, et renvoie le resultat demandé
    admin( groupUID ) - la fonction ne fait que ce qu'un admin du groupe indiqué aurait le droit de faire
    speaker( groupUID ), member( groupUID ), veiwer( groupUID ) - même chose
    user - la fonction ne fait que ce que l'utiliateur a le droit de faire (vérifications via l'argument user)

    La procédure a suivre est la suivante : quand une fonction possède un certain niveau de droit,
    elle ne peut appeler une fonction possédant un niveau de droit plus large que si
    1 ) on a au préalable vérifié que l'utilisateur possédait effectivement ces droits.
    ou
    2 ) on s'est assuré que l'opération effectuée par cet appel particulier de la fonction était dans les droits
    de l'utilisateur

    Les resolvers de base de mutation et query ont des droits user.

    Les fonctions qui ne modifient pas la BDD et ne renvoient pas de données sur la BDD n'ont pas de rights.
*/

/**
 * Résolveurs des différentes requêtes GraphQL
 */

export const resolvers = {
    Query: {

        // User queries de base
        // @rights connectedOrOnplatal
        user: async function (root, args, context: Context): Promise<User> {
            if(context.models.auth.isConnectedOrOnplatal()) {
                return context.models.user.getUser(args.uid);
            }
            throw new AuthenticationError("Not connected or on-platal");
        },

        // Group queries de base
        // @rights connectedOrOnplatal
        group: async function (root, args, context: Context): Promise<Group> {
            if (context.models.auth.isConnectedOrOnplatal()) {
                return context.models.group.getGroup(args.gid);
            }
            throw new AuthenticationError("Not connected or on-platal");
        },

        // @rights connectedOrOnplatal
        simpleGroup: async function (obj, args, context: Context): Promise<SimpleGroup> {
            if (context.models.auth.isConnectedOrOnplatal()) {
                return context.models.group.getSimpleGroup(args.gid);
            }
            throw new AuthenticationError("Not connected or on-platal");
        },

        // @rights connectedOrOnplatal
        metaGroup: async function (obj, args, context: Context): Promise<MetaGroup> {
            if (context.models.auth.isConnectedOrOnplatal()) {
                return context.models.group.getMetaGroup(args.gid);
            }
            throw new AuthenticationError("Not connected or on-platal");
        },

        // Message queries de base
        //message -> not implemented -> message(mid: ID!): Message

        // @rights membre d'un groupe author ou d'un groupe recipient
        announcement: async function (root, args, context: Context): Promise<Announcement> {
            //TODO : verifier les autorisations
            throw "Not implemented";
            return context.models.message.getAnnouncement(args.mid);
            throw new AuthenticationError("Not connected or on-platal");
        },

        // @rights membre d'un groupe author ou d'un groupe recipient
        event: async function (root, args, context: Context): Promise<Event> {
            //TODO : verifier les autorisations
            throw "Not implemented";
            return context.models.message.getEvent(args.mid);
            throw new AuthenticationError("Not connected or on-platal");
        },

        // @rights membre du groupe recipient
        privatePost: async function (root, args, context: Context): Promise<PrivatePost> {
            //TODO : verifier les autorisations
            throw "Not implemented";
            return context.models.message.getPrivatePost(args.mid);
            throw new AuthenticationError("Not connected or on-platal");
        },

        // @rights viewer du groupe recipient
        question: async function (root, args, context: Context): Promise<Question> {
            //TODO : verifier les autorisations
            throw "Not implemented";
            return context.models.message.getQuestion(args.mid);
            throw new AuthenticationError("Not connected or on-platal");
        },

        // @rights viewer du groupe author
        answer: async function (root, args, context: Context): Promise<Answer> {
            //TODO : verifier les autorisations
            throw "Not implemented";
            return context.models.message.getAnswer(args.mid);
            throw new AuthenticationError("Not connected or on-platal");
        },

        // Request queries de base
        //request -> not implemented -> request(rid: ID!): Request

        // @rights admin du groupe destinaire ou le user émetteur
        userJoinGroupRequest: async function (root, args, context: Context): Promise<UserJoinGroup> {
            //TODO : verifier les autorisations
            throw "Not implemented";
            return context.models.request.getUserJoinGroupRequest(args.rid);
            throw new AuthenticationError("Not connected or on-platal");
        },

        // @rights admin du groupe émetteur ou destinataire
        groupJoinMetagroupRequest: async function (root, args, context: Context): Promise<GroupJoinMetagroup> {
            //TODO : verifier les autorisations
            throw "Not implemented";
            return context.models.request.getGroupJoinMetagroupRequest(args.rid);
            throw new AuthenticationError("Not connected or on-platal");
        },

        // @rights admin du groupe émetteur ou destinataire
        groupCoauthorEventRequest: async function (root, args, context: Context): Promise<GroupCoauthorEvent> {
            //TODO : verifier les autorisations
            throw "Not implemented";
            return context.models.request.getGroupCoauthorEventRequest(args.rid);
            throw new AuthenticationError("Not connected or on-platal");
        },

        // Tous les Messages visibles par un utilisateur(dont le uid, et donc les autorisations, est passé par context)
        // @rights member of groups
        allMessages: async function (root, args, context: Context): Promise<Message[]> {
            let groups = context.models.auth.groupsMember();
            return context.models.message.getAllMessages(groups);
        },

        // @rights member of groups
        allAnnouncements: async function (root, args, context: Context): Promise<Announcement[]> {
            let groups = context.models.auth.groupsMember();
            return context.models.message.getAllAnnouncements(groups);
        },

        // @rights member of groups
        allEvents: async function (root, args, context: Context): Promise<Event[]> {
            let groups = context.models.auth.groupsMember();
            return context.models.message.getAllEvents(groups);
        },

        // @rights member of groups
        allPrivatePosts: async function (root, args, context: Context): Promise<PrivatePost[]> {
            let groups = context.models.auth.groupsMember();
            return context.models.message.getAllPrivatePosts(groups);
        },

        // Tous les Groupes visibles par un utilisateur.
        // Correspondrait au sous - champ "viewerOf" de User, volontairement non - défini comme tel.Tous les autres cas de figure sont couverts par les sous - champs "<permission>Of" de User
        // @rights viewer of groups
        allGroups: async function (root, args, context: Context): Promise<Group[]> {
            let visibleGroupCollection = context.models.auth.groupsViewer();
            return context.models.group.getAllGroupsByCollection(visibleGroupCollection);
        },

        // @rights viewer of groups
        allSimpleGroups: async function (root, args, context: Context): Promise<SimpleGroup[]> {
            let visibleGroupCollection = context.models.auth.groupsViewer();
            return context.models.group.getAllSimpleGroups(visibleGroupCollection.simpleGroups);
        },

        // @rights supervisor of groups
        supervisorOf: async function (root, args, context: Context): Promise<Group[]> {
            let supervisorGroupCollection = context.models.auth.groupsSupervisor();
            return context.models.group.getAllGroupsByCollection(supervisorGroupCollection);
        },

        // TOL
        // @rights connectedOrOnplatal
        searchTOL: async function (root, args, context: Context): Promise<User[]> {
            if (context.models.auth.isConnectedOrOnplatal()) {
                return context.models.user.searchTOL(args);
            }
            throw new AuthenticationError("Not connected or on-platal");
        }
    },

    Mutation: {

        // Groups - independent mutations
        // @rights authenticated
        editProfile: async function (root, args, context: Context): Promise<User> {
            if(context.models.auth.isAuthenticated()) {
                return context.models.user.editProfile(args);
            }
            throw new AuthenticationError("Not authenticated");
        },

        // Viewer mutations
        // @rights viewer
        likeGroup: async function (root, args, context: Context): Promise<boolean> {
            if (context.models.auth.isViewer(args.gid)) {
                return context.models.group.likeGroup(args.gid)
            }
            throw new AuthenticationError("Not a viewer");
        },

        // @rights viewer
        unlikeGroup: async function (root, args, context: Context): Promise<boolean> {
            if (context.models.auth.isViewer(args.gid)) {
                return context.models.group.unlikeGroup(args.gid)
            }
            throw new AuthenticationError("Not a viewer");
        },

        // @rights member d'un groupe author ou recipient
        userParticipate: async function (root, args, context: Context): Promise<boolean> {
            throw "Not implemented";
            //TODO : Vérifier les autorisations
            return context.models.message.userParticipate(context.user.uid, args.forEvent);
            throw new AuthenticationError("Not a viewer");
        },

        // @rights member d'un groupe author ou recipient
        userUnparticipate: async function (root, args, context: Context): Promise<boolean> {
            throw "Not implemented";
            //TODO : Vérifier les autorisations
            return context.models.message.userUnparticipate(context.user.uid, args.forEvent);
            throw new AuthenticationError("Not a viewer");
        },

        // @rights viewer
        userRequestJoinGroup: async function (root, args, context: Context): Promise<UserJoinGroup> {
            if(context.models.auth.isViewer(args.toGroup)) {
                return context.models.request.userRequestJoinGroup(args.toGroup, args.comment);
            }
            throw new AuthenticationError("Not a viewer");
        },

        // @rights viewer
        createQuestion: async function (root, args, context: Context): Promise<Question> {
            if (context.models.auth.isViewer(args.toGroup)) {
                return context.models.message.createQuestion(args.toGroup, args.title, args.content);
            }
            throw new AuthenticationError("Not a viewer");
        },

        // @rights viewer du groupe et author de la question
        editQuestion: async function (root, args, context: Context): Promise<Question> {
            throw "Not implemented";
            // TODO : Vérifier qu'il est l'auteur de la question et viewer
            return context.models.message.editQuestion(args.questionToEdit, args.title, args.content);
            throw new AuthenticationError("Not a viewer");
        },

        // @rights viewer du groupe et author de la question
        removeQuestion: async function (root, args, context: Context): Promise<boolean> {
            throw "Not implemented";
            // TODO : Vérifier qu'il est l'auteur de la question et viewer
            return context.models.message.removeQuestion(args.questionToRemove);
            throw new AuthenticationError("Not a viewer");
        },

        // Member mutations
        // @rights member
        userLeaveGroup: async function (root, args, context: Context): Promise<boolean> {
            if (context.models.auth.isMember(args.gid)) {
                return context.models.group.userLeaveGroup(args.gid);
            }
            throw new AuthenticationError("Not a member");
        },

        // @rights member
        createPrivatePost: async function (root, args, context: Context): Promise<PrivatePost> {
            if (context.models.auth.isMember(args.toGroup)) {
                return context.models.message.createPrivatePost(args.toGroup, args.title, args.content);
            }
            throw new AuthenticationError("Not a member");
        },

        // @rights member du groupe et author du post
        editPrivatePost: async function (root, args, context: Context): Promise<PrivatePost> {
            throw "Not implemented";
            // TODO : Vérifier qu'il est l'auteur du post et member
            return context.models.message.editPrivatePost(args.privatePostToEdit, args.title, args.content);
            throw new AuthenticationError("Not a member");
        },

        // @rights member du groupe et author du post
        removePrivatePost: async function (root, args, context: Context): Promise<boolean> {
            throw "Not implemented";
            // TODO : Vérifier qu'il est l'auteur du post et member
            return context.models.message.removePrivatePost(args.privatePostToRemove);
            throw new AuthenticationError("Not a member");
        },

        // Speaker mutations
        // @rights speaker
        writePostsSummary: async function (root, args, context: Context): Promise<boolean> {
            if (context.models.auth.isSpeaker(args.forGroup)) {
                return context.models.group.writePostsSummary(args.forGroup, args.content);
            }
            throw new AuthenticationError("Not a speaker");
        },

        // @rights speaker
        groupParticipate: async function (root, args, context: Context): Promise<boolean> {
            if (context.models.auth.isSpeaker(args.gid)) {
                return context.models.message.groupParticipate(args.gid, args.forEvent);
            }
            throw new AuthenticationError("Not a speaker");
        },

        // @rights speaker
        groupUnparticipate: async function (root, args, context: Context): Promise<boolean> {
            if (context.models.auth.isSpeaker(args.gid)) {
                return context.models.message.groupUnparticipate(args.gid, args.forEvent);
            }
            throw new AuthenticationError("Not a speaker");
        },

        // @rights speaker du groupe émetteur
        groupRequestCoauthorEvent: async function (root, args, context: Context): Promise<GroupCoauthorEvent> {
            if (context.models.auth.isSpeaker(args.fromGroup)) {
                return context.models.request.groupRequestCoauthorEvent(args.fromGroup, args.toGroup, args.forEvent, args.comment);
            }
            throw new AuthenticationError("Not a speaker");
        },

        // @rights speaker du groupe émetteur
        createAnnouncement: async function (root, args, context: Context): Promise<Announcement> {
            if (context.models.auth.isSpeaker(args.fromGroup)) {
                return context.models.message.createAnnouncement(args.fromGroup, new GroupSet(args.toGroups), args.title, args.content, args.forEvent);
            }
            throw new AuthenticationError("Not a speaker");
        },

        // @rights speaker du groupe émetteur
        editAnnouncement: async function (root, args, context: Context): Promise<Announcement> {
            throw "Not implemented";
            // TODO : Vérifier les autorisations.
            return context.models.message.editAnnouncement(args.announcementToEdit, args.title, args.content, args.forEvent);
            throw new AuthenticationError("Not a speaker");
        },

        // @rights speaker du groupe émetteur
        removeAnnouncement: async function (root, args, context: Context): Promise<boolean> {
            throw "Not implemented";
            // TODO : Vérifier les autorisations
            return context.models.message.removeAnnouncement(args.announcementToRemove);
            throw new AuthenticationError("Not a speaker");
        },

        // @rights speaker du groupe émetteur
        createEvent: async function (root, args, context: Context): Promise<Event> {
            if (context.models.auth.isSpeaker(args.fromGroup)) {
                return context.models.message.createEvent(args.fromGroup,
                    new GroupSet(args.toGroups), 
                    args.title, 
                    args.content, 
                    args.location, 
                    args.startTime, 
                    args.endTime, 
                    args.forAnnouncement);
            }
            throw new AuthenticationError("Not a speaker");
        },

        // @rights speaker du groupe émetteur
        editEvent: async function (root, args, context: Context): Promise<Event> {
            throw "Not implemented";
            // TODO : Vérifier les autorisations.
            return context.models.message.editEvent(args.eventToEdit,
                args.title,
                args.content,
                args.location,
                args.startTime,
                args.endTime,
                args.forAnnouncement);
            throw new AuthenticationError("Not a speaker");
        },

        // @rights speaker du groupe émetteur
        removeEvent: async function (root, args, context: Context): Promise<boolean> {
            throw "Not implemented";
            // TODO : Vérifier les autorisations
            return context.models.message.removeEvent(args.eventToRemove);
            throw new AuthenticationError("Not a speaker");
        },

        // @rights speaker du groupe
        createAnswer: async function (root, args, context: Context): Promise<Answer> {
            throw "Not implemented";
            // TODO : Vérifier les autorisations.
            return context.models.message.createAnswer(args.forQuestion, args.title, args.content);
            throw new AuthenticationError("Not a speaker");
        },

        // @rights speaker du groupe
        editAnswer: async function (root, args, context: Context): Promise<Answer> {
            throw "Not implemented";
            // TODO : Vérifier les autorisations.
            return context.models.message.editAnswer(args.answerToEdit, args.title, args.content);
            throw new AuthenticationError("Not a speaker");
        },

        // @rights speaker du groupe
        removeAnswer: async function (root, args, context: Context): Promise<boolean> {
            throw "Not implemented";
            // TODO : Vérifier les autorisations
            return context.models.message.removeAnswer(args.answerToRemove);
            throw new AuthenticationError("Not a speaker");
        },

        // Admin mutations
        // @rights admin of parent group
        createSubgroup: async function (root, args, context: Context): Promise<Group> {
            if(context.models.auth.isAdmin(args.fromGroup)) {
                return context.models.group.createSubgroup(args);
            }
            throw new AuthenticationError("Not an admin");
        },

        // @rights admin
        makeAdmin: async function (root, args, context: Context): Promise<User> {
            if (context.models.auth.isAdmin(args.forGroup)) {
                return context.models.group.makeAdmin(args.forGroup, args.uid);
            }
            throw new AuthenticationError("Not an admin");
        },

        // @rights admin
        unmakeAdmin: async function (root, args, context: Context): Promise<User> {
            if (context.models.auth.isAdmin(args.forGroup)) {
                return context.models.group.unmakeAdmin(args.forGroup, args.uid);
            }
            throw new AuthenticationError("Not an admin");
        },

        // @rights admin
        makeSpeaker: async function (root, args, context: Context): Promise<User> {
            if (context.models.auth.isAdmin(args.forGroup)) {
                return context.models.group.makeSpeaker(args.forGroup, args.uid);
            }
            throw new AuthenticationError("Not an admin");
        },

        // @rights admin
        unmakeSpeaker: async function (root, args, context: Context): Promise<User> {
            if (context.models.auth.isAdmin(args.forGroup)) {
                return context.models.group.unmakeSpeaker(args.forGroup, args.uid);
            }
            throw new AuthenticationError("Not an admin");
        },

        // @rights admin
        editGroup: async function (root, args, context: Context): Promise<Group> {
            if (context.models.auth.isAdmin(args.forGroup)) {
                return context.models.group.editGroup(args);
            }
            throw new AuthenticationError("Not an admin");
        },

        // @rights admin
        addVisibilityEdge: async function (root, args, context: Context): Promise<boolean> {
            if (context.models.auth.isAdmin(args.forGroup)) {
                return context.models.group.addVisibilityEdge(args.forGroup, args.visibleBy);
            }
            throw new AuthenticationError("Not an admin");
        },

        // @rights admin
        removeVisibilityEdge: async function (root, args, context: Context): Promise<boolean> {
            if (context.models.auth.isAdmin(args.forGroup)) {
                return context.models.group.removeVisibilityEdge(args.forGroup, args.visibleBy);
            }
            throw new AuthenticationError("Not an admin");
        },

        // @rights admin du groupe émetteur
        groupRequestJoinMetagroup: async function (root, args, context: Context): Promise<GroupJoinMetagroup> {
            if (context.models.auth.isAdmin(args.fromGroup)) {
                return context.models.request.groupRequestJoinMetagroup(args.fromGroup, args.toMetagroup, args.comment);
            }
            throw new AuthenticationError("Not an admin");
        },

        // @rights admin du groupe destinataire
        acceptUserJoinRequest: async function (root, args, context: Context): Promise<boolean> {
            let req = await UserJoinGroup.tryCreate(args.request);
            throw "Not implemented";
            //TODO : Vérifier les autorisations
            //if (context.models.auth.isAdmin(req.to)) {
                return context.models.request.acceptUserJoinRequest(req, args.comment);
            throw new AuthenticationError("Not an admin");
        },

        // @rights admin du groupe destinataire
        acceptGroupJoinRequest: async function (root, args, context: Context): Promise<boolean> {
            let req = await GroupJoinMetagroup.tryCreate(args.request);
            throw "Not implemented";
            //TODO : Vérifier les autorisations
            //if (context.models.auth.isAdmin(req.to)) {
            return context.models.request.acceptGroupJoinRequest(req, args.comment);
            throw new AuthenticationError("Not an admin");
        },

        // @rights admin du groupe destinataire
        refuseUserJoinRequest: async function (root, args, context: Context): Promise<boolean> {
            let req = await UserJoinGroup.tryCreate(args.request);
            throw "Not implemented";
            //TODO : Vérifier les autorisations
            //if (context.models.auth.isAdmin(req.to)) {
            return context.models.request.refuseUserJoinRequest(req, args.comment);
            throw new AuthenticationError("Not an admin");
        },

        // @rights admin du groupe destinataire
        refuseGroupJoinRequest: async function (root, args, context: Context): Promise<boolean> {
            let req = await GroupJoinMetagroup.tryCreate(args.request);
            throw "Not implemented";
            //TODO : Vérifier les autorisations
            //if (context.models.auth.isAdmin(req.to)) {
            return context.models.request.refuseGroupJoinRequest(req, args.comment);
            throw new AuthenticationError("Not an admin");
        },

        // @rights admin
        removeUser: async function (root, args, context: Context): Promise<User> {
            if(context.models.auth.isAdmin(args.fromGroup)) {
                return context.models.group.removeUser(args.fromGroup, args.uid);
            }
            throw new AuthenticationError("Not an admin");
        },

        // @rights admin du groupe destinataire
        acceptGroupCoauthorEventRequest: async function (root, args, context: Context): Promise<boolean> {
            // Pour l'instant, ce n'est pas a implémenter...
            let req = await GroupCoauthorEvent.tryCreate(args.request);
            throw "Not implemented";
            //TODO : Vérifier les autorisations
            //if (context.models.auth.isAdmin(req.to)) {
            return context.models.request.acceptGroupCoauthorEventRequest(req, args.comment);
            throw new AuthenticationError("Not an admin");
        },

        // @rights admin du groupe destinataire
        refuseGroupCoauthorEventRequest: async function (root, args, context: Context): Promise<boolean> {
            // Pour l'instant, ce n'est pas a implémenter...
            let req = await GroupCoauthorEvent.tryCreate(args.request);
            throw "Not implemented";
            //TODO : Vérifier les autorisations
            //if (context.models.auth.isAdmin(req.to)) {
            return context.models.request.refuseGroupCoauthorEventRequest(req, args.comment);
            throw new AuthenticationError("Not an admin");
        },

        // @rights admin du groupe
        censorQuestion: async function (root, args, context: Context): Promise<boolean> {
            throw "Not implemented";
            //TODO : Vérifier les autorisations
            return context.models.message.censorQuestion(args.questionToCensor);
            throw new AuthenticationError("Not an admin");
        },

        // @rights admin du groupe
        censorAnswer: async function (root, args, context: Context): Promise<boolean> {
            throw "Not implemented";
            //TODO : Vérifier les autorisations
            return context.models.message.censorAnswer(args.answerToCensor);
            throw new AuthenticationError("Not an admin");
        },

        // @rights admin du groupe
        censorPrivatePost: async function (root, args, context: Context): Promise<boolean> {
            throw "Not implemented";
            //TODO : Vérifier les autorisations
            return context.models.message.censorPrivatePost(args.privatePostToCensor);
            throw new AuthenticationError("Not an admin");
        },

        // @rights admin d'un groupe author
        censorAnnouncement: async function (root, args, context: Context): Promise<boolean> {
            throw "Not implemented";
            //TODO : Vérifier les autorisations
            return context.models.message.censorAnnouncement(args.announcementToCensor);
            throw new AuthenticationError("Not an admin");
        },

        // @rights admin d'un groupe author
        censorEvent: async function (root, args, context: Context): Promise<boolean> {
            throw "Not implemented";
            //TODO : Vérifier les autorisations
            return context.models.message.censorEvent(args.eventToCensor);
            throw new AuthenticationError("Not an admin");
        },

        // Supervisor mutations
        // @rights supervisor
        takeAdminRights : async function(root, args, context: Context): Promise<boolean> {
            if (context.models.auth.isSupervisor(args.forGroup)) {
                return context.models.group.takeAdminRights(args.forGroup, context.user.uid);
            }
            throw new AuthenticationError("Not a supervisor");
        },

        // @rights supervisor
        releaseAdminRights: async function (root, args, context: Context): Promise<boolean> {
            if (context.models.auth.isSupervisor(args.forGroup)) {
                return context.models.group.releaseAdminRights(args.forGroup, context.user.uid);
            }
            throw new AuthenticationError("Not a supervisor");
        }
    }
};