diff --git a/admin-panel b/admin-panel index b67c5934..f76a7b4b 160000 --- a/admin-panel +++ b/admin-panel @@ -1 +1 @@ -Subproject commit b67c59349261c3656f58c19fe820d89a97185305 +Subproject commit f76a7b4bb8428da29e05f6fd26d008c5f55260a4 diff --git a/package.json b/package.json index 4d095b64..b1f4588a 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ "geolib": "^2.0.24", "graphql": "^14.1.1", "graphql-tag": "^2.10.1", + "grpc": "^1.22.2", "lodash": "^4.17.11", "mongo-dot-notation": "^1.2.0", "mongoose": "^5.4.13", diff --git a/release b/release index 970b7568..78a3e6ec 100644 --- a/release +++ b/release @@ -1 +1 @@ -1.0.54 +1.0.55 diff --git a/src/FirebaseManager.js b/src/FirebaseManager.js index 06719e13..2637d64f 100644 --- a/src/FirebaseManager.js +++ b/src/FirebaseManager.js @@ -138,7 +138,7 @@ export const createMatchChat = ({ // does not throw export const sendMessage = async ({ - chatID, messageType, content, sender_id, + chatID, messageType, content, sender_id, contentType, }) => { try { const db = getFirebaseDb(); @@ -151,7 +151,7 @@ export const sendMessage = async ({ const messageSetObj = { documentID: newMessageRef.id, type: messageType, - contentType: 'TEXT', + contentType: contentType || 'TEXT', content, timestamp: now, }; @@ -221,19 +221,61 @@ export const notifyEndorsementChatAcceptedRequest = async ({ }); }; -export const sendMatchmakerRequestMessage = async ({ chatID, sentBy, requestText }) => sendMessage({ +export const sendMatchmakerRequestMessage = async ({ chatID, - messageType: 'MATCHMAKER_REQUEST', - content: requestText, - sender_id: sentBy._id.toString(), -}); + sentBy, + requestText, + likedPhoto, + likedPrompt, +}) => { + const contentObj = {}; + let contentType = 'TEXT'; + if (requestText) { + contentObj.message = requestText; + } + if (likedPhoto) { + contentObj.likedPhoto = likedPhoto; + contentType = 'PHOTO_LIKE'; + } else if (likedPrompt) { + contentObj.likedPrompt = likedPrompt; + contentType = 'PROMPT_LIKE'; + } + sendMessage({ + chatID, + messageType: 'MATCHMAKER_REQUEST', + content: contentType === 'TEXT' ? (requestText || '') : JSON.stringify(contentObj), + contentType, + sender_id: sentBy._id.toString(), + }); +}; -export const sendPersonalRequestMessage = async ({ chatID, sentBy, requestText }) => sendMessage({ +export const sendPersonalRequestMessage = async ({ chatID, - messageType: 'PERSONAL_REQUEST', - content: requestText, - sender_id: sentBy._id.toString(), -}); + sentBy, + requestText, + likedPhoto, + likedPrompt, +}) => { + const contentObj = {}; + let contentType = 'TEXT'; + if (requestText) { + contentObj.message = requestText; + } + if (likedPhoto) { + contentObj.likedPhoto = likedPhoto; + contentType = 'PHOTO_LIKE'; + } else if (likedPrompt) { + contentObj.likedPrompt = likedPrompt; + contentType = 'PROMPT_LIKE'; + } + sendMessage({ + chatID, + messageType: 'PERSONAL_REQUEST', + content: contentType === 'TEXT' ? (requestText || '') : JSON.stringify(contentObj), + contentType, + sender_id: sentBy._id.toString(), + }); +}; export const sendPushNotification = async ({ deviceToken, title, body }) => { try { diff --git a/src/models/DetachedProfile.js b/src/models/DetachedProfile.js index e8dfb8e2..0dff0f7d 100644 --- a/src/models/DetachedProfile.js +++ b/src/models/DetachedProfile.js @@ -32,6 +32,9 @@ extend type Mutation{ # ID is optional, for testing only approveNewDetachedProfile(approveDetachedProfileInput: ApproveDetachedProfileInput!): UserMutationResponse! + # rejects the detached profile + rejectDetachedProfile(rejectDetachedProfileInput: RejectDetachedProfileInput!): DetachedProfileMutationResponse! + # creator can edit the detached profile editDetachedProfile(editDetachedProfileInput: EditDetachedProfileInput!): DetachedProfileMutationResponse! @@ -86,6 +89,15 @@ input ApproveDetachedProfileInput { } `; +const rejectDetachedProfileInput = ` +input RejectDetachedProfileInput { + # id of the user rejecting + user_id: ID! + # id of the detached profile + detachedProfile_id: ID! +} +`; + const editDetachedProfileInput = ` input EditDetachedProfileInput { # id of the profile being edited @@ -163,6 +175,7 @@ export const typeDef = queryRoutes + mutationRoutes + createDetachedProfileInput + approveDetachedProfileInput + + rejectDetachedProfileInput + editDetachedProfileInput + detachedProfileType + detachedProfileMutationResponse; diff --git a/src/models/MatchModel.js b/src/models/MatchModel.js index 07e4f05a..ac2dc984 100644 --- a/src/models/MatchModel.js +++ b/src/models/MatchModel.js @@ -1,3 +1,6 @@ +import { ImageContainerSchema } from './ImageSchemas'; +import { QuestionUserResponseSchema } from './ContentModels'; + const mongoose = require('mongoose'); const { Schema } = mongoose; @@ -38,8 +41,10 @@ input CreateMatchRequestInput { # Discovered user receiving the request receivedByUser_id: ID! - # Optional text that goes along with the chat request + # Optional text that goes along with the like requestText: String + likedPhoto: CreateImageContainer + likedPrompt: QuestionUserResponseInput } `; @@ -70,6 +75,10 @@ type Match{ receivedByUser_id: ID! receivedByUser: User isMatchmakerMade: Boolean! + + requestText: String + likedPhoto: ImageContainer + likedPrompt: QuestionUserResponse sentForUserStatus: RequestResponse! sentForUserStatusLastUpdated: String! @@ -121,6 +130,10 @@ const MatchSchema = new Schema({ receivedByUser_id: { type: Schema.Types.ObjectId, required: true, index: true }, isMatchmakerMade: { type: Boolean, required: true }, + requestText: { type: String, required: false }, + likedPhoto: { type: ImageContainerSchema, required: false }, + likedPrompt: { type: QuestionUserResponseSchema, required: false }, + sentForUserStatus: { type: String, required: true, diff --git a/src/models/UserActionModel.js b/src/models/UserActionModel.js index d117b88f..668fe693 100644 --- a/src/models/UserActionModel.js +++ b/src/models/UserActionModel.js @@ -57,6 +57,7 @@ enum UserActionType { SKIP_CARD SEND_FR ACCEPT_FR + REJECT_FR EDIT_DP UNKNOWN JOIN_EVENT @@ -82,6 +83,7 @@ const ActionTypes = { SKIP_CARD: 'SKIP_CARD', SEND_FR: 'SEND_FR', ACCEPT_FR: 'ACCEPT_FR', + REJECT_FR: 'REJECT_FR', EDIT_DP: 'EDIT_DP', JOIN_EVENT: 'JOIN_EVENT', UNKNOWN: 'UNKNOWN', @@ -329,6 +331,17 @@ export const recordEditDP = ({ creator, detachedProfile }) => { recordAction({ user_id: creator._id, action }); }; +export const recordRejectFR = ({ rejectDetachedProfileInput, detachedProfile }) => { + const action = { + actor_id: rejectDetachedProfileInput.user_id, + user_ids: [rejectDetachedProfileInput.user_id, detachedProfile.creatorUser_id], + description: `$0 rejected profile from $1 with ${detachedProfile.questionResponses.length} promtps`, + actionType: ActionTypes.REJECT_FR, + }; + recordAction({ user_id: rejectDetachedProfileInput.user_id, action }); + recordAction({ user_id: detachedProfile.creatorUser_id, action }); +}; + export const recordJoinEvent = ({ user, event }) => { const action = { actor_id: user._id, diff --git a/src/models/UserModel.js b/src/models/UserModel.js index c1b150de..a51d07fc 100644 --- a/src/models/UserModel.js +++ b/src/models/UserModel.js @@ -2,7 +2,6 @@ import { MatchingDemographicsSchema, MatchingPreferencesSchema } from './Matchin import { ImageContainerSchema } from './ImageSchemas'; import { EdgeSummarySchema } from './MatchModel'; import { EndorsementEdgeSchema } from './EndorsementModels'; -import { USERS_ALREADY_MATCHED_ERROR } from '../resolvers/ResolverErrorStrings'; import { BioSchema, BoastSchema, DontSchema, DoSchema, InterestSchema, @@ -541,14 +540,6 @@ export const createUserObject = (userInput, skipTimestamps) => { }; export const receiveRequest = (me, otherUser, match_id, isFromFriend) => { - const alreadyExists = me.edgeSummaries.find( - edgeSummary => (edgeSummary.otherUser_id.toString() === otherUser._id.toString()), - ); - if (alreadyExists !== undefined) { - return Promise.reject( - new Error(USERS_ALREADY_MATCHED_ERROR), - ); - } me.edgeSummaries.push({ otherUser_id: otherUser._id, match_id, @@ -563,14 +554,6 @@ export const receiveRequest = (me, otherUser, match_id, isFromFriend) => { }; export const sendRequest = (me, otherUser, match_id) => { - const alreadyExists = me.edgeSummaries.find( - edgeSummary => (edgeSummary.otherUser_id.toString() === otherUser._id.toString()), - ); - if (alreadyExists !== undefined) { - return Promise.reject( - new Error(USERS_ALREADY_MATCHED_ERROR), - ); - } me.personalMatchesSentCount += 1; me.edgeSummaries.push({ otherUser_id: otherUser._id, diff --git a/src/resolvers/DetachedProfileResolvers/DetachedProfileResolver.js b/src/resolvers/DetachedProfileResolvers/DetachedProfileResolver.js index a4ea9ca7..d0cda950 100644 --- a/src/resolvers/DetachedProfileResolvers/DetachedProfileResolver.js +++ b/src/resolvers/DetachedProfileResolvers/DetachedProfileResolver.js @@ -5,7 +5,7 @@ import { CREATE_DETACHED_PROFILE_ERROR, DELETE_DETACHED_PROFILE_ERROR, EDIT_DETACHED_PROFILE_ERROR, - GET_USER_ERROR, + GET_USER_ERROR, REJECT_PROFILE_ERROR, VIEW_DETACHED_PROFILE_ERROR, WRONG_CREATOR_ERROR, } from '../ResolverErrorStrings'; @@ -16,6 +16,7 @@ import { getAndValidateUsersAndDetachedProfileObjects } from './DetachedProfileR import { editDetachedProfileResolver } from './EditDetachedProfile'; import { generateSentryErrorForResolver } from '../../SentryHelper'; import { datadogStats } from '../../DatadogHelper'; +import { rejectDetachedProfileResolver } from './RejectDetachedProfile'; const debug = require('debug')('dev:DetachedProfileResolvers'); const errorLog = require('debug')('error:DetachedProfileResolvers'); @@ -99,7 +100,7 @@ export const resolvers = { errorLog(`error occurred editing detached profile: ${e}`); generateSentryErrorForResolver({ resolverType: 'mutation', - routeName: 'editDetachedProfileInput', + routeName: 'editDetachedProfile', args: { editDetachedProfileInput }, errorMsg: e, errorName: EDIT_DETACHED_PROFILE_ERROR, @@ -119,7 +120,7 @@ export const resolvers = { errorLog(`error occurred approving detached profile: ${e}`); generateSentryErrorForResolver({ resolverType: 'mutation', - routeName: 'approveDetachedProfileInput', + routeName: 'approveDetachedProfile', args: { approveDetachedProfileInput }, errorMsg: e, errorName: APPROVE_PROFILE_ERROR, @@ -130,6 +131,26 @@ export const resolvers = { }; } }, + rejectDetachedProfile: async (_source, { rejectDetachedProfileInput }) => { + functionCallConsole('Reject Profile Called'); + datadogStats.increment('server.stats.detached_profile_rejected'); + try { + return rejectDetachedProfileResolver({ rejectDetachedProfileInput }); + } catch (e) { + errorLog(`error occurred rejecting detached profile :${e}`); + generateSentryErrorForResolver({ + resolverType: 'mutation', + routeName: 'rejectDetachedProfile', + args: { rejectDetachedProfileInput }, + errorMsg: e, + errorName: REJECT_PROFILE_ERROR, + }); + return { + success: false, + message: REJECT_PROFILE_ERROR, + }; + } + }, // TODO deleteDetachedProfile: async (_source, { creator_id, detachedProfile_id }) => { functionCallConsole('deleteDetachedProfile called'); diff --git a/src/resolvers/DetachedProfileResolvers/RejectDetachedProfile.js b/src/resolvers/DetachedProfileResolvers/RejectDetachedProfile.js new file mode 100644 index 00000000..1a1f114e --- /dev/null +++ b/src/resolvers/DetachedProfileResolvers/RejectDetachedProfile.js @@ -0,0 +1,49 @@ +import { User } from '../../models/UserModel'; +import { + GET_DETACHED_PROFILE_ERROR, + GET_USER_ERROR, WRONG_USER_ERROR, +} from '../ResolverErrorStrings'; +import { DetachedProfile } from '../../models/DetachedProfile'; +import { recordRejectFR } from '../../models/UserActionModel'; + +export const rejectDetachedProfileResolver = async ({ rejectDetachedProfileInput }) => { + const user = await User.findById(rejectDetachedProfileInput.user_id) + .exec() + .catch(err => err); + let detachedProfile = await DetachedProfile + .findById(rejectDetachedProfileInput.detachedProfile_id) + .exec() + .catch(err => err); + if (!user || user instanceof Error) { + return { + success: false, + message: GET_USER_ERROR, + }; + } + if (!detachedProfile || detachedProfile instanceof Error) { + return { + success: false, + message: GET_DETACHED_PROFILE_ERROR, + }; + } + if (detachedProfile.status === 'accepted') { + // no-op if detached profile has already been approved + return { + success: true, + detachedProfile, + }; + } + if (user.phoneNumber !== detachedProfile.phoneNumber) { + return { + success: false, + message: WRONG_USER_ERROR, + }; + } + detachedProfile.status = 'declined'; + detachedProfile = await detachedProfile.save(); + recordRejectFR({ rejectDetachedProfileInput, detachedProfile }); + return { + success: true, + detachedProfile, + }; +}; diff --git a/src/resolvers/DiscoveryQueueResolvers/GetDiscoveryCardsResolver.js b/src/resolvers/DiscoveryQueueResolvers/GetDiscoveryCardsResolver.js index aaf7b2ba..3002edea 100644 --- a/src/resolvers/DiscoveryQueueResolvers/GetDiscoveryCardsResolver.js +++ b/src/resolvers/DiscoveryQueueResolvers/GetDiscoveryCardsResolver.js @@ -251,7 +251,7 @@ export const addCardsToCache = async ({ user, discoveryQueue, nCardsToAdd }) => let cardsToPush = []; for (const ignoreSkipList of [false, true]) { for (const includeLocation of [true, false]) { - for (const widerAge of [0, 3, 5, 10]) { + for (const widerAge of [0, 2]) { for (const seededOnly of [true, false]) { let seededOnlyFinal = seededOnly; if (discoveryQueue.decidedDiscoveryItems diff --git a/src/resolvers/MatchingResolvers/CreateNewMatch.js b/src/resolvers/MatchingResolvers/CreateNewMatch.js index afe38555..788ad2bd 100644 --- a/src/resolvers/MatchingResolvers/CreateNewMatch.js +++ b/src/resolvers/MatchingResolvers/CreateNewMatch.js @@ -2,7 +2,7 @@ import nanoid from 'nanoid'; import { receiveRequest, sendRequest, User } from '../../models/UserModel'; import { GET_USER_ERROR, SEND_MATCH_PREFERENCES_SILENT_FAIL, - SEND_MATCH_REQUEST_ERROR, USERS_ALREADY_MATCHED_ERROR, + SEND_MATCH_REQUEST_ERROR, USERS_ALREADY_MATCHED_SILENT_FAIL, WRONG_CREATOR_ERROR, } from '../ResolverErrorStrings'; import { DiscoveryQueue } from '../../models/DiscoveryQueueModel'; @@ -50,7 +50,13 @@ const verifyPreferencesMatch = ({ }; export const createNewMatchResolver = async ({ - sentByUser_id, sentForUser_id, receivedByUser_id, _id = mongoose.Types.ObjectId(), requestText, + sentByUser_id, + sentForUser_id, + receivedByUser_id, + _id = mongoose.Types.ObjectId(), + requestText, + likedPhoto, + likedPrompt, }) => { const matchID = _id; // determine whether this is a matchmaker request or a personal request @@ -101,29 +107,6 @@ export const createNewMatchResolver = async ({ } const initialSentFor = sentFor.toObject(); const initialReceivedBy = receivedBy.toObject(); - for (const matchedUser_id in sentFor.edgeSummaries.map(edge => edge.otherUser_id.toString())) { - if (matchedUser_id.toString() === receivedBy._id.toString()) { - return { - success: false, - message: USERS_ALREADY_MATCHED_ERROR, - }; - } - } - const sentForDemographics = sentFor.matchingDemographics; - const sentForPreferences = sentFor.matchingPreferences; - const receivedByDemographics = receivedBy.matchingDemographics; - const receivedByPreferences = receivedBy.matchingPreferences; - if (!verifyPreferencesMatch({ - sentForDemographics, - sentForPreferences, - receivedByDemographics, - receivedByPreferences, - })) { - return { - success: true, - message: SEND_MATCH_PREFERENCES_SILENT_FAIL, - }; - } const sentForDiscoveryPromise = DiscoveryQueue.findOne({ user_id: sentForUser_id }) .exec() @@ -161,6 +144,63 @@ export const createNewMatchResolver = async ({ const initialSentForDiscovery = sentForDiscovery.toObject(); const initialReceivedByDiscovery = receivedByDiscovery.toObject(); + // update discovery queues - this happens whether or not the match fails + sentForDiscovery.currentDiscoveryItems = sentForDiscovery.currentDiscoveryItems + .filter(item => item.user_id.toString() !== receivedByUser_id.toString()); + const sentForDiscoveryUpdatePromise = matchmakerMade + ? sentForDiscovery.save().catch(err => err) + : Promise.resolve(null); + receivedByDiscovery.currentDiscoveryItems = receivedByDiscovery.currentDiscoveryItems + .filter(item => item.user_id.toString() !== sentForUser_id.toString()); + const receivedByDiscoveryUpdatePromise = receivedByDiscovery.save().catch(err => err); + + // fail and return if users already matched, or if preferences aren't lined up + // also record a skip action in sentBy's decidedDiscoveryItems + for (const matchedUser_id in sentFor.edgeSummaries.map(edge => edge.otherUser_id.toString())) { + if (matchedUser_id.toString() === receivedBy._id.toString()) { + sentByDiscovery.decidedDiscoveryItems.push({ + user_id: receivedByUser_id.toString(), + action: 'skip', + }); + sentByDiscovery.save().catch(err => err); + return { + success: true, + message: USERS_ALREADY_MATCHED_SILENT_FAIL, + }; + } + } + const sentForDemographics = sentFor.matchingDemographics; + const sentForPreferences = sentFor.matchingPreferences; + const receivedByDemographics = receivedBy.matchingDemographics; + const receivedByPreferences = receivedBy.matchingPreferences; + if (!verifyPreferencesMatch({ + sentForDemographics, + sentForPreferences, + receivedByDemographics, + receivedByPreferences, + })) { + sentByDiscovery.decidedDiscoveryItems.push({ + user_id: receivedByUser_id.toString(), + action: 'skip', + }); + sentByDiscovery.save().catch(err => err); + return { + success: true, + message: SEND_MATCH_PREFERENCES_SILENT_FAIL, + }; + } + + // if users haven't already been peared, and preferences line up, record pear/match + // in decidedDiscoveryItems + sentByDiscovery.currentDiscoveryItems = sentByDiscovery.currentDiscoveryItems + .filter(item => item.user_id.toString() !== receivedByUser_id.toString()); + sentByDiscovery.decidedDiscoveryItems.push({ + user_id: receivedByUser_id.toString(), + action: matchmakerMade ? 'pear' : 'match', + }); + const sentByDiscoveryUpdatePromise = sentByDiscovery.save().catch(err => err); + + // create the match object let endorsementEdge = null; if (matchmakerMade) { datadogStats.increment('server.stats.match_request_matchmaker_sent'); @@ -176,7 +216,6 @@ export const createNewMatchResolver = async ({ const firebaseId = nanoid(20); - // create the match object const matchInput = { _id: matchID, sentByUser_id, @@ -186,6 +225,15 @@ export const createNewMatchResolver = async ({ firebaseChatDocumentID: firebaseId, firebaseChatDocumentPath: getChatDocPathFromId(firebaseId), }; + if (likedPhoto) { + matchInput.likedPhoto = likedPhoto; + } + if (likedPrompt) { + matchInput.likedPrompt = likedPrompt; + } + if (requestText) { + matchInput.requestText = requestText; + } if (!matchmakerMade) { matchInput.sentForUserStatus = 'accepted'; } @@ -216,23 +264,6 @@ export const createNewMatchResolver = async ({ }) .catch(err => err); - // update discovery queues - sentByDiscovery.currentDiscoveryItems = sentByDiscovery.currentDiscoveryItems - .filter(item => item.user_id.toString() !== receivedByUser_id.toString()); - sentByDiscovery.decidedDiscoveryItems.push({ - user_id: receivedByUser_id.toString(), - action: matchmakerMade ? 'pear' : 'match', - }); - const sentByDiscoveryUpdatePromise = sentByDiscovery.save().catch(err => err); - sentForDiscovery.currentDiscoveryItems = sentForDiscovery.currentDiscoveryItems - .filter(item => item.user_id.toString() !== receivedByUser_id.toString()); - const sentForDiscoveryUpdatePromise = matchmakerMade - ? sentForDiscovery.save().catch(err => err) - : Promise.resolve(null); - receivedByDiscovery.currentDiscoveryItems = receivedByDiscovery.currentDiscoveryItems - .filter(item => item.user_id.toString() !== sentForUser_id.toString()); - const receivedByDiscoveryUpdatePromise = receivedByDiscovery.save().catch(err => err); - const [match, sentForEdgeResult, receivedByEdgeResult, @@ -256,7 +287,6 @@ export const createNewMatchResolver = async ({ || sentForDiscoveryResult instanceof Error || receivedByDiscoveryResult instanceof Error) { let errorMessage = ''; - let responseMessage = SEND_MATCH_REQUEST_ERROR; if (match instanceof Error) { errorLog(`Failed to create match Object: ${match.toString()}`); errorMessage += match.toString(); @@ -269,16 +299,10 @@ export const createNewMatchResolver = async ({ if (sentForEdgeResult instanceof Error) { errorLog(`Sent For Edge Failure:${sentForEdgeResult.toString()}`); errorMessage += sentForEdgeResult.toString(); - if (sentForEdgeResult.toString() === (new Error(USERS_ALREADY_MATCHED_ERROR)).toString()) { - responseMessage = USERS_ALREADY_MATCHED_ERROR; - } } if (receivedByEdgeResult instanceof Error) { errorLog(`Received By Edge Failure:${receivedByEdgeResult.toString()}`); errorMessage += receivedByEdgeResult.toString(); - if (receivedByEdgeResult.toString() === (new Error(USERS_ALREADY_MATCHED_ERROR)).toString()) { - responseMessage = USERS_ALREADY_MATCHED_ERROR; - } } if (createChatResult instanceof Error) { errorMessage += createChatResult.toString(); @@ -350,15 +374,17 @@ export const createNewMatchResolver = async ({ }); return { success: false, - message: responseMessage, + message: SEND_MATCH_REQUEST_ERROR, }; } - // send push notifications + // send push notifications and chat messages if (matchmakerMade) { sendMatchmakerRequestMessage({ chatID: firebaseId, sentBy, requestText: requestText || '', + likedPhoto, + likedPrompt, }); if (endorsementEdge) { const endorsementChatId = endorsementEdge.firebaseChatDocumentID; @@ -378,6 +404,8 @@ export const createNewMatchResolver = async ({ chatID: firebaseId, sentBy, requestText: requestText || '', + likedPhoto, + likedPrompt, }); } sendMatchReceivedByPushNotification({ receivedBy }); diff --git a/src/resolvers/ResolverErrorStrings.js b/src/resolvers/ResolverErrorStrings.js index a1fed139..341ceb1e 100644 --- a/src/resolvers/ResolverErrorStrings.js +++ b/src/resolvers/ResolverErrorStrings.js @@ -9,18 +9,20 @@ export const CREATE_DETACHED_PROFILE_ERROR = 'Failed to create profile.'; export const EDIT_DETACHED_PROFILE_ERROR = 'Couldn\'t edit profile.'; export const EDIT_ENDORSEMENT_ERROR = 'Couldn\'t complete this operation.'; export const WRONG_CREATOR_ERROR = 'Matchmaker did not endorse this user.'; +export const WRONG_USER_ERROR = 'User is not authorized to take this action'; export const VIEW_DETACHED_PROFILE_ERROR = 'Failed to perform this operation.'; export const DELETE_DETACHED_PROFILE_ERROR = 'Couldn\'t delete this profile.'; export const CANT_ENDORSE_YOURSELF = 'Can\'t create a profile for yourself.'; export const ALREADY_MADE_PROFILE = 'Already made a profile for this person.'; export const APPROVE_PROFILE_ERROR = 'Couldn\'t approve this profile.'; +export const REJECT_PROFILE_ERROR = 'Couldn\'t decline this friend request.'; export const ALREADY_APPROVED_PROFILE = 'This profile has already been approved.'; -export const FORCE_FEED_UPDATE_ERROR = 'Couldn\'t update feed.'; export const SKIP_DISCOVERY_ITEM_ERROR = 'Couldn\'t perform this operation.'; export const GET_DISCOVERY_CARDS_ERROR = 'Couldn\t retrieve new profiles.'; export const SEND_MATCH_REQUEST_ERROR = 'Couldn\'t send match request.'; export const SEND_MATCH_PREFERENCES_SILENT_FAIL = 'Users outside each others\'s preferences: silent fail'; export const USERS_ALREADY_MATCHED_ERROR = 'These users have already been Peared!'; +export const USERS_ALREADY_MATCHED_SILENT_FAIL = 'Users have already been Peared: silent fail'; export const ACCEPT_MATCH_REQUEST_ERROR = 'Couldn\'t accept match request.'; export const REJECT_MATCH_REQUEST_ERROR = 'Couldn\'t perform action on match request.'; export const UNMATCH_ERROR = 'Couldn\'t perform action on match.'; @@ -29,5 +31,4 @@ export const EVENT_NOT_FOUND = 'Event not found.'; export const ADD_EVENT_CODE_ERROR = 'An error occurred: couldn\'t add event code.'; export const COULDNT_RECORD_ACTION = 'Couldn\'t record action.'; -export const FORCE_FEED_UPDATE_SUCCESS = 'Updated feed successfully.'; export const DELETE_DETACHED_PROFILE_SUCCESS = 'Deleted profile successfully.'; diff --git a/src/tests/AttachProfileVars.js b/src/tests/AttachProfileVars.js index 9d46e26b..4b930780 100644 --- a/src/tests/AttachProfileVars.js +++ b/src/tests/AttachProfileVars.js @@ -2,7 +2,7 @@ import { AVERY_ID, AVERY_PROFILE_MADE_D_ID, BRIAN_ID, - BRIAN_PROFILE_SAMMI_D_ID, + BRIAN_PROFILE_SAMMI_D_ID, JOEL_ID, JOEL_PROFILE_BRIAN_D_ID, JOSH_ID, JOSH_PROFILE_SOPHIA_D_ID, MADE_ID, @@ -129,3 +129,10 @@ export const ATTACH_SOPHIA2_PROFILE_VARIABLES = { vibes: [], }, }; + +export const REJECT_JOEL1_PROFILE_VARIABLES = { + rejectDetachedProfileInput: { + user_id: JOEL_ID, + detachedProfile_id: JOEL_PROFILE_BRIAN_D_ID, + }, +}; diff --git a/src/tests/CreateDetachedProfileVars.js b/src/tests/CreateDetachedProfileVars.js index 1416912e..304a772d 100644 --- a/src/tests/CreateDetachedProfileVars.js +++ b/src/tests/CreateDetachedProfileVars.js @@ -1,7 +1,7 @@ import { AVERY_PROFILE_MADE_D_ID, BRIAN_ID, - BRIAN_PROFILE_SAMMI_D_ID, + BRIAN_PROFILE_SAMMI_D_ID, JOEL_PROFILE_BRIAN_D_ID, JOSH_ID, JOSH_PROFILE_SOPHIA_D_ID, MADE_ID, @@ -33,7 +33,7 @@ export const CREATE_AVERY1_DETACHED_PROFILE_VARIABLES = { questionResponses: [ { author_id: MADE_ID, - authorFirstName: '', + authorFirstName: 'Made', question_id: QUESTION1_ID, question: { _id: QUESTION1_ID, @@ -64,7 +64,7 @@ export const CREATE_BRIAN1_DETACHED_PROFILE_VARIABLES = { questionResponses: [ { author_id: SAMMI_ID, - authorFirstName: '', + authorFirstName: 'Sammi', question_id: QUESTION2_ID, question: { _id: QUESTION2_ID, @@ -91,12 +91,10 @@ export const CREATE_JOSH1_DETACHED_PROFILE_VARIABLES = { firstName: 'Josh', gender: 'male', phoneNumber: '7897897898', - boasts: [], - roasts: [], questionResponses: [ { author_id: SOPHIA_ID, - authorFirstName: '', + authorFirstName: 'Sophia', question_id: QUESTION3_ID, question: { _id: QUESTION3_ID, @@ -109,7 +107,6 @@ export const CREATE_JOSH1_DETACHED_PROFILE_VARIABLES = { responseBody: 'josh response 1-1', }, ], - vibes: [], }, }; @@ -121,13 +118,11 @@ export const CREATE_SAMMI1_DETACHED_PROFILE_VARIABLES = { firstName: 'Sammi', phoneNumber: '9788733736', gender: 'female', - boasts: [], - roasts: [], questionResponses: [ { _id: SAMMI_QR1_ID, author_id: JOSH_ID, - authorFirstName: '', + authorFirstName: 'Josh', question_id: QUESTION1_ID, question: { _id: QUESTION1_ID, @@ -140,7 +135,6 @@ export const CREATE_SAMMI1_DETACHED_PROFILE_VARIABLES = { responseBody: 'sammi response 1-1', }, ], - vibes: [], }, }; @@ -151,13 +145,11 @@ export const CREATE_SAMMI2_DETACHED_PROFILE_VARIABLES = { creatorFirstName: '', firstName: 'Sammi', phoneNumber: '9788733736', - boasts: [], - roasts: [], questionResponses: [ { _id: SAMMI_QR2_ID, author_id: BRIAN_ID, - authorFirstName: '', + authorFirstName: 'Brian', question_id: QUESTION1_ID, question: { _id: QUESTION1_ID, @@ -172,7 +164,7 @@ export const CREATE_SAMMI2_DETACHED_PROFILE_VARIABLES = { { _id: SAMMI_QR3_ID, author_id: BRIAN_ID, - authorFirstName: '', + authorFirstName: 'Brian', question_id: QUESTION2_ID, question: { _id: QUESTION2_ID, @@ -185,7 +177,6 @@ export const CREATE_SAMMI2_DETACHED_PROFILE_VARIABLES = { responseBody: 'sammi response 2-2', }, ], - vibes: [], }, }; @@ -196,10 +187,7 @@ export const CREATE_MADE1_DETACHED_PROFILE_VARIABLES = { creatorFirstName: '', firstName: 'Made', phoneNumber: '6092402838', - boasts: [], - roasts: [], questionResponses: [], - vibes: [], }, }; @@ -210,10 +198,22 @@ export const CREATE_UMA1_DETACHED_PROFILE_VARIABLES = { creatorFirstName: '', firstName: 'Uma', phoneNumber: '9784296614', - boasts: [], - roasts: [], - questionResponses: [], - vibes: [], + questionResponses: [ + { + author_id: BRIAN_ID, + authorFirstName: 'Brian', + question_id: QUESTION2_ID, + question: { + _id: QUESTION2_ID, + questionText: 'What\'s your friend\'s weird flex?', + questionTextWithName: 'What\'s {{name}}\'s weird flex?', + questionType: 'freeResponse', + suggestedResponses: [], + tags: [], + }, + responseBody: 'uma response 1-1', + }, + ], }, }; @@ -224,10 +224,7 @@ export const CREATE_SOPHIA1_DETACHED_PROFILE_VARIABLES = { creatorFirstName: '', firstName: 'Sophia', phoneNumber: '9165189165', - boasts: [], - roasts: [], questionResponses: [], - vibes: [], }, }; @@ -238,9 +235,17 @@ export const CREATE_SOPHIA2_DETACHED_PROFILE_VARIABLES = { creatorFirstName: '', firstName: 'Sophia', phoneNumber: '9165189165', - boasts: [], - roasts: [], questionResponses: [], - vibes: [], + }, +}; + +export const CREATE_JOEL1_DETACHED_PROFILE_VARIABLES = { + detachedProfileInput: { + _id: JOEL_PROFILE_BRIAN_D_ID, + creatorUser_id: BRIAN_ID, + creatorFirstName: 'Brian', + firstName: 'Joel', + phoneNumber: '7777777777', + questionResponses: [], }, }; diff --git a/src/tests/CreateTestDB.js b/src/tests/CreateTestDB.js index 144f5771..70be7810 100644 --- a/src/tests/CreateTestDB.js +++ b/src/tests/CreateTestDB.js @@ -20,6 +20,7 @@ import { CREATE_SOPHIA1_DETACHED_PROFILE_VARIABLES, CREATE_SOPHIA2_DETACHED_PROFILE_VARIABLES, CREATE_UMA1_DETACHED_PROFILE_VARIABLES, + CREATE_JOEL1_DETACHED_PROFILE_VARIABLES, } from './CreateDetachedProfileVars'; import { ATTACH_AVERY1_PROFILE_VARIABLES, @@ -30,7 +31,7 @@ import { ATTACH_SAMMI2_PROFILE_VARIABLES, ATTACH_SOPHIA1_PROFILE_VARIABLES, ATTACH_SOPHIA2_PROFILE_VARIABLES, - ATTACH_UMA1_PROFILE_VARIABLES, + ATTACH_UMA1_PROFILE_VARIABLES, REJECT_JOEL1_PROFILE_VARIABLES, } from './AttachProfileVars'; import { ACCEPT_REQUEST_1_VARIABLES, @@ -55,7 +56,7 @@ import { } from './UpdateFeedVars'; import { VIEW_AVERY1_PROFILE_VARIABLES, - VIEW_BRIAN1_PROFILE_VARIABLES, + VIEW_BRIAN1_PROFILE_VARIABLES, VIEW_JOEL1_PROFILE_VARIABLES, VIEW_JOSH1_PROFILE_VARIABLES, VIEW_MADE1_PROFILE_VARIABLES, VIEW_SAMMI1_PROFILE_VARIABLES, @@ -133,6 +134,7 @@ export const createDetachedProfiles = [ CREATE_UMA1_DETACHED_PROFILE_VARIABLES, CREATE_SOPHIA1_DETACHED_PROFILE_VARIABLES, CREATE_SOPHIA2_DETACHED_PROFILE_VARIABLES, + CREATE_JOEL1_DETACHED_PROFILE_VARIABLES, ]; export const updateUserFirstNames = [ @@ -165,6 +167,7 @@ export const viewDetachedProfiles = [ VIEW_UMA1_PROFILE_VARIABLES, VIEW_SOPHIA1_PROFILE_VARIABLES, VIEW_SOPHIA2_PROFILE_VARIABLES, + VIEW_JOEL1_PROFILE_VARIABLES, ]; export const attachProfiles = [ @@ -179,6 +182,10 @@ export const attachProfiles = [ ATTACH_SOPHIA2_PROFILE_VARIABLES, ]; +export const rejectProfiles = [ + REJECT_JOEL1_PROFILE_VARIABLES, +]; + export const updateUsers = [ UPDATE_AVERY_USER_VARIABLES, UPDATE_BRIAN_USER_VARIABLES, diff --git a/src/tests/MatchActionVars.js b/src/tests/MatchActionVars.js index 3b0d3933..a6d708ee 100644 --- a/src/tests/MatchActionVars.js +++ b/src/tests/MatchActionVars.js @@ -14,6 +14,12 @@ import { MATCH6_ID, EMPTY_USER_ID1, EMPTY_USER_ID2, + SAMMI_PHOTO2, + QUESTION1_ID, + QUESTION2_ID, + QUESTION3_ID, + AVERY_PHOTO1, + SAMMI_QR5_ID, } from './TestsContants'; export const SEND_PERSONAL_REQUEST_1_VARIABLES = { @@ -23,6 +29,7 @@ export const SEND_PERSONAL_REQUEST_1_VARIABLES = { sentForUser_id: JOSH_ID, receivedByUser_id: SAMMI_ID, requestText: 'I\'d like to match with you!', + likedPhoto: SAMMI_PHOTO2, }, }; @@ -32,6 +39,22 @@ export const SEND_PERSONAL_REQUEST_2_VARIABLES = { sentByUser_id: SOPHIA_ID, sentForUser_id: SOPHIA_ID, receivedByUser_id: AVERY_ID, + likedPrompt: { + author_id: MADE_ID, + authorFirstName: '', + question_id: QUESTION1_ID, + question: { + _id: QUESTION1_ID, + questionText: 'How did they end up on the cover of Forbes?', + questionTextWithName: 'How did {{name}} end up on the cover of Forbes?', + questionType: 'freeResponse', + suggestedResponses: [], + tags: [ + 'personality', + ], + }, + responseBody: 'avery response 1-1', + }, }, }; @@ -42,6 +65,20 @@ export const SEND_MATCHMAKER_REQUEST_3_VARIABLES = { sentForUser_id: SAMMI_ID, receivedByUser_id: UMA_ID, requestText: 'You two would make a great Pear!', + likedPrompt: { + author_id: BRIAN_ID, + authorFirstName: 'Brian', + question_id: QUESTION2_ID, + question: { + _id: QUESTION2_ID, + questionText: 'What\'s your friend\'s weird flex?', + questionTextWithName: 'What\'s {{name}}\'s weird flex?', + questionType: 'freeResponse', + suggestedResponses: [], + tags: [], + }, + responseBody: 'uma response 1-1', + }, }, }; @@ -51,6 +88,7 @@ export const SEND_MATCHMAKER_REQUEST_4_VARIABLES = { sentByUser_id: BRIAN_ID, sentForUser_id: UMA_ID, receivedByUser_id: AVERY_ID, + likedPhoto: AVERY_PHOTO1, }, }; @@ -60,6 +98,23 @@ export const SEND_MATCHMAKER_REQUEST_5_VARIABLES = { sentByUser_id: MADE_ID, sentForUser_id: AVERY_ID, receivedByUser_id: SAMMI_ID, + likedPrompt: { + _id: SAMMI_QR5_ID, + author_id: BRIAN_ID, + question_id: QUESTION2_ID, + question: { + _id: QUESTION3_ID, + questionText: 'People only want one thing, and it’s disgusting 😫. What does your friend want?', + questionTextWithName: 'People only want one thing, and it’s disgusting 😫. What does {{name}} want?', + questionType: 'freeResponse', + suggestedResponses: [], + tags: [ + 'personality', + ], + }, + authorFirstName: 'Brian', + responseBody: 'sammi response 2-3', + }, }, }; diff --git a/src/tests/Mutations.js b/src/tests/Mutations.js index c7220e99..37cec7d8 100644 --- a/src/tests/Mutations.js +++ b/src/tests/Mutations.js @@ -222,26 +222,21 @@ export const ATTACH_DETACHED_PROFILE = gql` _id fullName endorser_ids - boasts { - _id - authorFirstName - content - } - roasts { - _id - authorFirstName - content - } - vibes { - _id - authorFirstName - content - } - bios { - _id - authorFirstName - content - } + } + } + } +`; + +export const REJECT_DETACHED_PROFILE = gql` + mutation RejectDetachedProfile($rejectDetachedProfileInput: RejectDetachedProfileInput!) { + rejectDetachedProfile(rejectDetachedProfileInput: $rejectDetachedProfileInput) { + success + message + detachedProfile { + _id + creatorFirstName + firstName + status } } } diff --git a/src/tests/ViewDetachedProfileVars.js b/src/tests/ViewDetachedProfileVars.js index e249d0dd..23bfef1c 100644 --- a/src/tests/ViewDetachedProfileVars.js +++ b/src/tests/ViewDetachedProfileVars.js @@ -1,3 +1,5 @@ +import { JOEL_ID, JOEL_PROFILE_BRIAN_D_ID } from './TestsContants'; + export const VIEW_AVERY1_PROFILE_VARIABLES = { user_id: '5c82162afec46c84e924a332', detachedProfile_id: '5c82162afec46c84e9241112', @@ -42,3 +44,8 @@ export const VIEW_SOPHIA2_PROFILE_VARIABLES = { user_id: '5c82162afec46c84e924a338', detachedProfile_id: '5c82162afec46c84e9241120', }; + +export const VIEW_JOEL1_PROFILE_VARIABLES = { + user_id: JOEL_ID, + detachedProfile_id: JOEL_PROFILE_BRIAN_D_ID, +}; diff --git a/src/tests/testFunctions/AttachDetachedProfilesTest.js b/src/tests/testFunctions/AttachDetachedProfilesTest.js index 3c3bdd71..b47f0bdc 100644 --- a/src/tests/testFunctions/AttachDetachedProfilesTest.js +++ b/src/tests/testFunctions/AttachDetachedProfilesTest.js @@ -1,6 +1,6 @@ -import { ATTACH_DETACHED_PROFILE } from '../Mutations'; +import { ATTACH_DETACHED_PROFILE, REJECT_DETACHED_PROFILE } from '../Mutations'; import { verbose } from '../../constants'; -import { attachProfiles } from '../CreateTestDB'; +import { attachProfiles, rejectProfiles } from '../CreateTestDB'; import { checkForAndLogErrors } from '../Utils'; const testLogger = require('debug')('tests:AttachDetachedProfilesTest'); @@ -34,5 +34,20 @@ export const runAttachDetachedProfilesTest = async (mutate) => { process.exit(1); } } + for (const rejectProfileVars of rejectProfiles) { + try { + const result = await mutate({ + mutation: REJECT_DETACHED_PROFILE, + variables: rejectProfileVars, + }); + if (verbose) { + verboseDebug(result); + } + checkForAndLogErrors(result, 'rejectDetachedProfile', errorLog); + } catch (e) { + errorLog((`${e}`)); + process.exit(1); + } + } successLog('***** Success Attaching Detached Profiles *****\n'); }; diff --git a/yarn.lock b/yarn.lock index 6fe7395b..9947c0fd 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3730,6 +3730,17 @@ grpc@^1.16.0: node-pre-gyp "^0.12.0" protobufjs "^5.0.3" +grpc@^1.22.2: + version "1.22.2" + resolved "https://registry.yarnpkg.com/grpc/-/grpc-1.22.2.tgz#1a60c728c692a93a85e855e35c2e0216654f0198" + integrity sha512-gaK59oAA5/mlOIn+hQO5JROPoAzsaGRpEMcrAayW5WGETS8QScpBoQ+XBxEWAAF0kbeGIELuGRCVEObKS1SLmw== + dependencies: + lodash.camelcase "^4.3.0" + lodash.clone "^4.5.0" + nan "^2.13.2" + node-pre-gyp "^0.13.0" + protobufjs "^5.0.3" + gtoken@^2.3.2: version "2.3.2" resolved "https://registry.yarnpkg.com/gtoken/-/gtoken-2.3.2.tgz#49890a866c1f44e173099be95515db5872a92151" @@ -5164,6 +5175,11 @@ nan@^2.0.0, nan@^2.9.2: resolved "https://registry.yarnpkg.com/nan/-/nan-2.12.1.tgz#7b1aa193e9aa86057e3c7bbd0ac448e770925552" integrity sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw== +nan@^2.13.2: + version "2.14.0" + resolved "https://registry.yarnpkg.com/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" + integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== + nanoid@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/nanoid/-/nanoid-2.0.1.tgz#deb55cac196e3f138071911dabbc3726eb048864" @@ -5282,6 +5298,22 @@ node-pre-gyp@^0.12.0: semver "^5.3.0" tar "^4" +node-pre-gyp@^0.13.0: + version "0.13.0" + resolved "https://registry.yarnpkg.com/node-pre-gyp/-/node-pre-gyp-0.13.0.tgz#df9ab7b68dd6498137717838e4f92a33fc9daa42" + integrity sha512-Md1D3xnEne8b/HGVQkZZwV27WUi1ZRuZBij24TNaZwUPU3ZAFtvT6xxJGaUVillfmMKnn5oD1HoGsp2Ftik7SQ== + dependencies: + detect-libc "^1.0.2" + mkdirp "^0.5.1" + needle "^2.2.1" + nopt "^4.0.1" + npm-packlist "^1.1.6" + npmlog "^4.0.2" + rc "^1.2.7" + rimraf "^2.6.1" + semver "^5.3.0" + tar "^4" + nodemon@^1.18.10: version "1.18.10" resolved "https://registry.yarnpkg.com/nodemon/-/nodemon-1.18.10.tgz#3ba63f64eb4c283cf3e4f75f30817e9d4f393afe"