oaeproject/Hilary

View on GitHub
packages/oae-discussions/lib/rest.js

Summary

Maintainability
F
5 days
Test Coverage
A
99%
/*!
 * Copyright 2014 Apereo Foundation (AF) Licensed under the
 * Educational Community License, Version 2.0 (the "License"); you may
 * not use this file except in compliance with the License. You may
 * obtain a copy of the License at
 *
 *     http://opensource.org/licenses/ECL-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an "AS IS"
 * BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
 * or implied. See the License for the specific language governing
 * permissions and limitations under the License.
 */

import * as DiscussionsAPI from 'oae-discussions';

import { forEach, forEachObjIndexed } from 'ramda';
import _ from 'underscore';

import { AuthzConstants } from 'oae-authz/lib/constants.js';
import * as OAE from 'oae-util/lib/oae.js';
import * as OaeUtil from 'oae-util/lib/util.js';

/**
 * @REST postDiscussionCreate
 *
 * Create a new discussion
 *
 * @Server      tenant
 * @Method      POST
 * @Path        /discussion/create
 * @FormParam   {string}            description         A longer description for the discussion
 * @FormParam   {string}            displayName         The display name of the discussion
 * @FormParam   {string[]}          [managers]          Unique identifier(s) for users and groups to add as managers of the discussion. The user creating the discussion will be added as a manager automatically
 * @FormParam   {string[]}          [members]           Unique identifier(s) for users and groups to add as members of the discussion
 * @FormParam   {string}            [visibility]        The visibility of the discussion. Defaults to the configured tenant default          [loggedin,private,public]
 * @Return      {BasicDiscussion}                       The created discussion
 * @HttpResponse                    200                 Discussion created
 * @HttpResponse                    400                 Must provide a display name for the discussion
 * @HttpResponse                    400                 Must provide a description for the discussion
 * @HttpResponse                    400                 A display name can be at most 1000 characters long
 * @HttpResponse                    400                 A description can be at most 10000 characters long
 * @HttpResponse                    400                 An invalid discussion visibility option has been provided
 * @HttpResponse                    400                 One or more target members being granted access are not authorized to become members on this discussion
 * @HttpResponse                    400                 One or more target members being granted access do not exist
 * @HttpResponse                    401                 Anonymous users cannot create a discussion
 */
OAE.tenantRouter.on('post', '/api/discussion/create', (request, response) => {
  // Ensure proper arrays for the additional members
  request.body.managers = OaeUtil.toArray(request.body.managers);
  request.body.members = OaeUtil.toArray(request.body.members);

  // Construct a hash for additional members that maps each user to their role
  const roles = {};
  forEach((manager) => {
    roles[manager] = AuthzConstants.role.MANAGER;
  }, request.body.managers);
  forEach((member) => {
    roles[member] = AuthzConstants.role.MEMBER;
  }, request.body.members);

  DiscussionsAPI.Discussions.createDiscussion(
    request.ctx,
    request.body.displayName,
    request.body.description,
    request.body.visibility,
    roles,
    null,
    (error, discussion) => {
      if (error) {
        return response.status(error.code).send(error.msg);
      }

      response.status(200).send(discussion);
    }
  );
});

/**
 * @REST postDiscussionDiscussionId
 *
 * Update a discussion
 *
 * @Server      tenant
 * @Method      POST
 * @Path        /discussion/{discussionId}
 * @PathParam   {string}            discussionId        The id of the discussion to update
 * @FormParam   {string}            [description]       Updated description for the discussion
 * @FormParam   {string}            [displayName]       Updated display name for the discussion
 * @FormParam   {string}            [visibility]        Updated visibility for the discussion           [loggedin,private,public]
 * @Return      {BasicDiscussion}                       The updated discussion
 * @HttpResponse                    200                 Discussion updated
 * @HttpResponse                    400                 A valid discussion id must be provided
 * @HttpResponse                    400                 A display name cannot be empty
 * @HttpResponse                    400                 A description cannot be empty
 * @HttpResponse                    400                 A display name can be at most 1000 characters long
 * @HttpResponse                    400                 A description can only be 10000 characters long
 * @HttpResponse                    400                 An invalid visibility was specified
 * @HttpResponse                    400                 An invalid field was specified
 * @HttpResponse                    400                 You should specify at least one profile field to update
 * @HttpResponse                    401                 You are not authorized to update this discussion
 * @HttpResponse                    404                 Could not find the specified discussion
 */
OAE.tenantRouter.on('post', '/api/discussion/:discussionId', (request, response) => {
  DiscussionsAPI.Discussions.updateDiscussion(
    request.ctx,
    request.params.discussionId,
    request.body,
    (error, discussion) => {
      if (error) {
        return response.status(error.code).send(error.msg);
      }

      response.status(200).send(discussion);
    }
  );
});

/**
 * @REST deleteDiscussionDiscussionId
 *
 * Delete a discussion
 *
 * @Server      tenant
 * @Method      DELETE
 * @Path        /discussion/{discussionId}
 * @PathParam   {string}        discussionId        The id of the discussion to delete
 * @HttpResponse                200                 Discussion deleted
 * @HttpResponse                400                 A valid discussion id must be provided
 * @HttpResponse                401                 You are not authorized to delete this discussion
 * @HttpResponse                404                 Could not find the specified discussion
 */
OAE.tenantRouter.on('delete', '/api/discussion/:discussionId', (request, response) => {
  DiscussionsAPI.Discussions.deleteDiscussion(request.ctx, request.params.discussionId, (error, message) => {
    if (error) {
      return response.status(error.code).send(error.msg);
    }

    return response.status(200).send(message);
  });
});

/**
 * @REST getDiscussionLibraryPrincipalId
 *
 * Get the discussions library items for a user or group
 *
 * @Server      tenant
 * @Method      GET
 * @Path        /discussion/library/{principalId}
 * @PathParam   {string}                principalId         The id of the principal whose discussion library to fetch
 * @QueryParam  {number}                [limit]             The maximum number of results to return. Default: 10
 * @QueryParam  {string}                [start]             The discussion paging token from which to start fetching discussions
 * @Return      {DiscussionsLibrary}                        The discussions library items for the specified user or group
 * @HttpResponse                        200                 Discussion library available
 * @HttpResponse                        400                 A user or group id must be provided
 * @HttpResponse                        401                 You do not have have access to this library
 */
OAE.tenantRouter.on('get', '/api/discussion/library/:principalId', (request, response) => {
  const limit = OaeUtil.getNumberParam(request.query.limit, 12, 1, 25);
  DiscussionsAPI.Discussions.getDiscussionsLibrary(
    request.ctx,
    request.params.principalId,
    request.query.start,
    limit,
    (error, discussions, nextToken) => {
      if (error) {
        return response.status(error.code).send(error.msg);
      }

      response.status(200).send({ results: discussions, nextToken });
    }
  );
});

/**
 * @REST deleteDiscussionLibraryPrincipalIdDiscussionId
 *
 * Remove a discussion from a discussion library
 *
 * @Server      tenant
 * @Method      DELETE
 * @Path        /discussion/library/{principalId}/{discussionId}
 * @PathParam   {string}                principalId         The id of the principal from whose discussion library to remove the discussion
 * @PathParam   {string}                discussionId        The id of the discussion to remove from the library
 * @HttpResponse                        200                 Discussion removed from library
 * @HttpResponse                        400                 A user or group id must be provided
 * @HttpResponse                        400                 An invalid discussion id was provided
 * @HttpResponse                        400                 The requested change results in a discussion with no managers
 * @HttpResponse                        400                 The specified discussion is not in this library
 * @HttpResponse                        401                 You are not authorized to remove a discussion from this library
 * @HttpResponse                        404                 Could not find the specified discussion
 */
OAE.tenantRouter.on('delete', '/api/discussion/library/:principalId/:discussionId', (request, response) => {
  DiscussionsAPI.Discussions.removeDiscussionFromLibrary(
    request.ctx,
    request.params.principalId,
    request.params.discussionId,
    (error) => {
      if (error) {
        return response.status(error.code).send(error.msg);
      }

      response.status(200).end();
    }
  );
});

/**
 * @REST getDiscussionDiscussionId
 *
 * Get a full discussion profile
 *
 * @Server      tenant
 * @Method      GET
 * @Path        /discussion/{discussionId}
 * @PathParam   {string}                discussionId        The id of the discussion to get
 * @Return      {Discussion}                                Full discussion profile
 * @HttpResponse                        200                 Discussion profile available
 * @HttpResponse                        400                 discussionId must be a valid resource id
 * @HttpResponse                        401                 You are not authorized to view this discussion
 * @HttpResponse                        404                 Could not find the specified discussion
 */
OAE.tenantRouter.on('get', '/api/discussion/:discussionId', (request, response) => {
  DiscussionsAPI.Discussions.getFullDiscussionProfile(request.ctx, request.params.discussionId, (error, discussion) => {
    if (error) {
      return response.status(error.code).send(error.msg);
    }

    response.status(200).send(discussion);
  });
});

/**
 * @REST postDiscussionDiscussionIdShare
 *
 * Share a discussion
 *
 * @Server      tenant
 * @Method      POST
 * @Path        /discussion/{discussionId}/share
 * @PathParam   {string}                discussionId        The id of the discussion to share
 * @FormParam   {string[]}              members             Unique identifier(s) for users and groups to share the discussion with
 * @Return      {void}
 * @HttpResponse                        200                 Discussion shared
 * @HttpResponse                        400                 A valid discussion id must be provided
 * @HttpResponse                        400                 At least one principal id needs to be passed in
 * @HttpResponse                        400                 Invalid principal id provided
 * @HttpResponse                        400                 One or more target members are not authorized to become members on this discussion
 * @HttpResponse                        400                 The discussion must at least be shared with 1 user or group
 * @HttpResponse                        400                 The member id: ... is not a valid member id
 * @HttpResponse                        401                 You are not authorized to share this discussion
 * @HttpResponse                        404                 Could not find the specified discussion
 */
OAE.tenantRouter.on('post', '/api/discussion/:discussionId/share', (request, response) => {
  let members = OaeUtil.toArray(request.body.members);
  members = _.compact(members);

  DiscussionsAPI.Discussions.shareDiscussion(request.ctx, request.params.discussionId, members, (error) => {
    if (error) {
      return response.status(error.code).send(error.msg);
    }

    response.status(200).end();
  });
});

/**
 * @REST postDiscussionDiscussionIdMembers
 *
 * Update the members of a discussion
 *
 * @Server      tenant
 * @Method      POST
 * @Path        /discussion/{discussionId}/members
 * @PathParam   {string}                    discussionId        The id of the discussion to update the members for
 * @BodyParam   {DiscussionMembersUpdate}   body                Object that describes the membership updates to apply to the discussion
 * @Return      {void}
 * @HttpResponse                            200                 Discussion members updated
 * @HttpResponse                            400                 A valid discussion id must be provided
 * @HttpResponse                            400                 Invalid principal id specified
 * @HttpResponse                            400                 Must specify at least one permission change to apply
 * @HttpResponse                            400                 One or more target members being granted access are not authorized to become members on this discussion
 * @HttpResponse                            400                 The requested change results in a discussion with no managers
 * @HttpResponse                            400                 An invalid role value was specified. Must either be a string, or false
 * @HttpResponse                            400                 You must specify at least one permission change
 * @HttpResponse                            401                 You are not authorized to update the permissions of this discussion
 * @HttpResponse                            404                 Could not find the specified discussion
 */
OAE.tenantRouter.on('post', '/api/discussion/:discussionId/members', (request, response) => {
  // Parse the incoming false values
  const permissionUpdates = {};
  forEachObjIndexed((value, key) => {
    permissionUpdates[key] = OaeUtil.castToBoolean(value);
  }, request.body);

  DiscussionsAPI.Discussions.setDiscussionPermissions(
    request.ctx,
    request.params.discussionId,
    permissionUpdates,
    (error) => {
      if (error) {
        return response.status(error.code).send(error.msg);
      }

      response.status(200).end();
    }
  );
});

/**
 * @REST getDiscussionDiscussionIdMembers
 *
 * Get the members of a discussion and their roles
 *
 * @Server      tenant
 * @Method      GET
 * @Path        /discussion/{discussionId}/members
 * @PathParam   {string}                discussionId        The id of the discussion to get the members for
 * @QueryParam  {number}                [limit]             The maximum number of results to return. Default: 10
 * @QueryParam  {string}                [start]             The discussion paging token from which to start fetching discussion members
 * @Return      {MembersResponse}                           Members of the specified discussion
 * @HttpResponse                        200                 Discussion members available
 * @HttpResponse                        400                 A valid discussion id must be provided
 * @HttpResponse                        401                 You are not authorized to view this discussion
 * @HttpResponse                        404                 Could not find the specified discussion
 */
OAE.tenantRouter.on('get', '/api/discussion/:discussionId/members', (request, response) => {
  const limit = OaeUtil.getNumberParam(request.query.limit, 10, 1, 25);
  DiscussionsAPI.Discussions.getDiscussionMembers(
    request.ctx,
    request.params.discussionId,
    request.query.start,
    limit,
    (error, members, nextToken) => {
      if (error) {
        return response.status(error.code).send(error.msg);
      }

      response.status(200).send({ results: members, nextToken });
    }
  );
});

/**
 * @REST getDiscussionDiscussionIdInvitations
 *
 * Get all the invitations associated to a discussion
 *
 * @Server      tenant
 * @Method      GET
 * @Path        /discussion/{discussionId}/invitations
 * @PathParam   {string}                discussionId        The id of the discussion for which to get invitations
 * @Return      {InvitationsResponse}                       The invitations associated to the discussion
 * @HttpResponse                        200                 Invitations available
 * @HttpResponse                        400                 A valid discussion id must be provided
 * @HttpResponse                        401                 You are not allowed to get invitations for this discussion
 * @HttpResponse                        404                 Discussion not available
 */
OAE.tenantRouter.on('get', '/api/discussion/:discussionId/invitations', (request, response) => {
  DiscussionsAPI.Discussions.getDiscussionInvitations(
    request.ctx,
    request.params.discussionId,
    (error, invitations) => {
      if (error) {
        return response.status(error.code).send(error.msg);
      }

      return response.status(200).send({ results: invitations });
    }
  );
});

/**
 * @REST postDiscussionDiscussionIdInvitationsEmailResend
 *
 * Resend an invitation to a discussion
 *
 * @Server      tenant
 * @Method      POST
 * @Path        /discussion/{discussionId}/invitations/{email}/resend
 * @PathParam   {string}                discussionId        The id of the discussion for which to get invitations
 * @PathParam   {string}                email               The email for which to resend the invitation
 * @Return      {void}
 * @HttpResponse                        200                 Invitation was resent
 * @HttpResponse                        400                 A valid discussion id must be provided
 * @HttpResponse                        400                 A valid email must be provided
 * @HttpResponse                        401                 You are not allowed to resend invitations for this discussion
 * @HttpResponse                        404                 Discussion not available
 * @HttpResponse                        404                 No invitation for the specified email exists for the discussion
 */
OAE.tenantRouter.on('post', '/api/discussion/:discussionId/invitations/:email/resend', (request, response) => {
  DiscussionsAPI.Discussions.resendDiscussionInvitation(
    request.ctx,
    request.params.discussionId,
    request.params.email,
    (error) => {
      if (error) {
        return response.status(error.code).send(error.msg);
      }

      return response.status(200).end();
    }
  );
});

/**
 * @REST getDiscussionDiscussionIdMessages
 *
 * Get the messages in a discussion
 *
 * @Server      tenant
 * @Method      GET
 * @Path        /discussion/{discussionId}/messages
 * @PathParam   {string}                discussionId        The id of the discussion for which to get the messages
 * @QueryParam  {number}                [limit]             The maximum number of results to return. Default: 10
 * @QueryParam  {string}                [start]             The messages paging token from which to start fetching messages
 * @Return      {MessagesResponse}                          The messages in the discussion
 * @HttpResponse                        200                 Discussion messages available
 * @HttpResponse                        400                 A messageBoxId must be specified
 * @HttpResponse                        400                 A timestamp cannot be in the future.
 * @HttpResponse                        400                 A timestamp cannot be null
 * @HttpResponse                        400                 A timestamp should be an integer
 * @HttpResponse                        400                 Must provide a valid discussion id
 * @HttpResponse                        401                 You are not authorized to view this discussion
 * @HttpResponse                        404                 Could not find the specified discussion
 */
OAE.tenantRouter.on('get', '/api/discussion/:discussionId/messages', (request, response) => {
  const limit = OaeUtil.getNumberParam(request.query.limit, 10, 1, 25);
  DiscussionsAPI.Discussions.getMessages(
    request.ctx,
    request.params.discussionId,
    request.query.start,
    limit,
    (error, messages, nextToken) => {
      if (error) {
        return response.status(error.code).send(error.msg);
      }

      response.status(200).send({ results: messages, nextToken });
    }
  );
});

/**
 * @REST postDiscussionDiscussionIdMessages
 *
 * Create a new message in a discussion
 *
 * @Server      tenant
 * @Method      POST
 * @Path        /discussion/{discussionId}/messages
 * @PathParam   {string}        discussionId        The id of the discussion to which to post the message
 * @FormParam   {string}        body                The body of the message
 * @FormParam   {number}        [replyTo]           The timestamp of the message to which this message is a reply. Not specifying this will create a top level comment
 * @Return      {Message}                           The created message
 * @HttpResponse                200                 Discussion message created
 * @HttpResponse                400                 A discussion body can only be 100000 characters long
 * @HttpResponse                400                 A discussion body must be provided
 * @HttpResponse                400                 A messageBoxId must be specified
 * @HttpResponse                400                 If the replyToCreated optional parameter is specified, it should point to an existing reply
 * @HttpResponse                400                 Invalid discussion id provided
 * @HttpResponse                400                 The body of the message must be specified
 * @HttpResponse                401                 You are not authorized to post messages to this discussion
 * @HttpResponse                404                 Could not find the specified discussion
 */
OAE.tenantRouter.on('post', '/api/discussion/:discussionId/messages', (request, response) => {
  DiscussionsAPI.Discussions.createMessage(
    request.ctx,
    request.params.discussionId,
    request.body.body,
    request.body.replyTo,
    (error, message) => {
      if (error) {
        return response.status(error.code).send(error.msg);
      }

      response.status(200).send(message);
    }
  );
});

/**
 * @REST deleteDiscussionDiscussionIdMessagesCreated
 *
 * Delete a message in a discussion
 *
 * @Server      tenant
 * @Method      DELETE
 * @Path        /discussion/{discussionId}/messages/{created}
 * @PathParam   {string}                discussionId        The id of the discussion from which to delete the message
 * @PathParam   {number}                created             The timestamp of the message that should be deleted
 * @Return      {Message}                                   When the message has been soft deleted (because it has replies), a stripped down message object representing the deleted message will be returned, with the `deleted` parameter set to `false`. If the message has been removed entirely, no message object will be returned
 * @HttpResponse                        200                 Discussion message deleted
 * @HttpResponse                        400                 A discussion id must be provided
 * @HttpResponse                        400                 A messageBoxId must be specified
 * @HttpResponse                        400                 A valid integer message created timestamp must be specified
 * @HttpResponse                        400                 The createdTimestamp should point to an existing message
 * @HttpResponse                        401                 You are not authorized to delete this message
 * @HttpResponse                        404                 Could not find the specified discussion
 * @HttpResponse                        404                 Could not find the specified message
 */
OAE.tenantRouter.on('delete', '/api/discussion/:discussionId/messages/:created', (request, response) => {
  DiscussionsAPI.Discussions.deleteMessage(
    request.ctx,
    request.params.discussionId,
    request.params.created,
    (error, message) => {
      if (error) {
        return response.status(error.code).send(error.msg);
      }

      response.status(200).send(message);
    }
  );
});