Skip to content

Commit

Permalink
feat: User tags backend adjustments (GSoC) (PalisadoesFoundation#2460)
Browse files Browse the repository at this point in the history
* add organization userTags connection

* add tests

* fix formatting issue

* adjustments and queries for tag screens

* fix linting
  • Loading branch information
meetulr authored Aug 15, 2024
1 parent 10a5203 commit db3d2f5
Show file tree
Hide file tree
Showing 17 changed files with 372 additions and 31 deletions.
9 changes: 6 additions & 3 deletions schema.graphql
Original file line number Diff line number Diff line change
Expand Up @@ -1514,6 +1514,8 @@ type Query {
getNoteById(id: ID!): Note!
getPledgesByUserId(orderBy: PledgeOrderByInput, userId: ID!, where: PledgeWhereInput): [FundraisingCampaignPledge]
getPlugins: [Plugin]
getUserTag(id: ID!): UserTag
getUserTagAncestors(id: ID!): [UserTag]
getVenueByOrgId(first: Int, orderBy: VenueOrderByInput, orgId: ID!, skip: Int, where: VenueWhereInput): [Venue]
getlanguage(lang_code: String!): [Translation]
groupChatById(id: ID!): GroupChat
Expand Down Expand Up @@ -1799,9 +1801,9 @@ input UpdateUserPasswordInput {
}

input UpdateUserTagInput {
_id: ID!
name: String!
tagColor: String!
tagColor: String
tagId: ID!
}

scalar Upload
Expand Down Expand Up @@ -1939,7 +1941,7 @@ type UserTag {
type UserTagsConnection {
edges: [UserTagsConnectionEdge!]!
pageInfo: DefaultConnectionPageInfo!
totalCount: PositiveInt
totalCount: Int
}

"""A default connection edge on the UserTag type for UserTagsConnection."""
Expand Down Expand Up @@ -1987,6 +1989,7 @@ input UserWhereInput {
type UsersConnection {
edges: [UsersConnectionEdge!]!
pageInfo: DefaultConnectionPageInfo!
totalCount: Int
}

"""A default connection edge on the User type for UsersConnection."""
Expand Down
30 changes: 26 additions & 4 deletions src/resolvers/Mutation/assignUserTag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -152,10 +152,32 @@ export const assignUserTag: MutationResolvers["assignUserTag"] = async (
);
}

// Assign the tag
await TagUser.create({
...args.input,
});
// assign all the ancestor tags
const allAncestorTags = [tag._id];
let currentTag = tag;
while (currentTag?.parentTagId) {
const currentParentTag = await OrganizationTagUser.findOne({
_id: currentTag.parentTagId,
}).lean();

if (currentParentTag) {
allAncestorTags.push(currentParentTag?._id);
currentTag = currentParentTag;
}
}

const assigneeId = args.input.userId;

const tagUserDocs = allAncestorTags.map((tagId) => ({
updateOne: {
filter: { userId: assigneeId, tagId },
update: { $setOnInsert: { userId: assigneeId, tagId } },
upsert: true,
setDefaultsOnInsert: true,
},
}));

await TagUser.bulkWrite(tagUserDocs);

return requestUser;
};
31 changes: 29 additions & 2 deletions src/resolvers/Mutation/unassignUserTag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,9 +145,36 @@ export const unassignUserTag: MutationResolvers["unassignUserTag"] = async (
);
}

// Get all the child tags of the current tag (including itself)
// on the OrganizationTagUser model
// The following implementation makes number of queries = max depth of nesting in the tag provided
let allTagIds: string[] = [];
let currentParents = [tag._id.toString()];

while (currentParents.length) {
allTagIds = allTagIds.concat(currentParents);
const foundTags = await OrganizationTagUser.find(
{
organizationId: tag.organizationId,
parentTagId: {
$in: currentParents,
},
},
{
_id: 1,
},
);
currentParents = foundTags
.map((tag) => tag._id.toString())
.filter((id: string | null) => id);
}

// Unassign the tag
await TagUser.deleteOne({
...args.input,
await TagUser.deleteMany({
tagId: {
$in: allTagIds,
},
userId: args.input.userId,
});

return requestUser;
Expand Down
4 changes: 2 additions & 2 deletions src/resolvers/Mutation/updateUserTag.ts
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@ export const updateUserTag: MutationResolvers["updateUserTag"] = async (

// Get the tag object
const existingTag = await OrganizationTagUser.findOne({
_id: args.input._id,
_id: args.input.tagId,
}).lean();

if (!existingTag) {
Expand Down Expand Up @@ -130,7 +130,7 @@ export const updateUserTag: MutationResolvers["updateUserTag"] = async (
// Update the title of the tag and return it
return await OrganizationTagUser.findOneAndUpdate(
{
_id: args.input._id,
_id: args.input.tagId,
},
{
name: args.input.name,
Expand Down
1 change: 1 addition & 0 deletions src/resolvers/Organization/userTags.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export const userTags: OrganizationResolvers["userTags"] = async (
OrganizationTagUser.find({
...filter,
organizationId: parent._id,
parentTagId: null,
})
.sort(sort)
.limit(parsedArgs.limit)
Expand Down
21 changes: 21 additions & 0 deletions src/resolvers/Query/getUserTag.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import { OrganizationTagUser } from "../../models";
import { errors, requestContext } from "../../libraries";
import type { QueryResolvers } from "../../types/generatedGraphQLTypes";
import { TAG_NOT_FOUND } from "../../constants";

export const getUserTag: QueryResolvers["getUserTag"] = async (
_parent,
args,
) => {
const userTag = await OrganizationTagUser.findById(args.id).lean();

if (!userTag) {
throw new errors.NotFoundError(
requestContext.translate(TAG_NOT_FOUND.MESSAGE),
TAG_NOT_FOUND.CODE,
TAG_NOT_FOUND.PARAM,
);
}

return userTag;
};
32 changes: 32 additions & 0 deletions src/resolvers/Query/getUserTagAncestors.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { OrganizationTagUser } from "../../models";
import { errors, requestContext } from "../../libraries";
import type { QueryResolvers } from "../../types/generatedGraphQLTypes";
import { TAG_NOT_FOUND } from "../../constants";

export const getUserTagAncestors: QueryResolvers["getUserTagAncestors"] =
async (_parent, args) => {
let currentTag = await OrganizationTagUser.findById(args.id).lean();

const tagAncestors = [currentTag];

while (currentTag?.parentTagId) {
const currentParent = await OrganizationTagUser.findById(
currentTag.parentTagId,
).lean();

if (currentParent) {
tagAncestors.push(currentParent);
currentTag = currentParent;
}
}

if (!currentTag) {
throw new errors.NotFoundError(
requestContext.translate(TAG_NOT_FOUND.MESSAGE),
TAG_NOT_FOUND.CODE,
TAG_NOT_FOUND.PARAM,
);
}

return tagAncestors.reverse();
};
4 changes: 4 additions & 0 deletions src/resolvers/Query/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@ import { getFundraisingCampaigns } from "./getFundraisingCampaigns";
import { getPledgesByUserId } from "./getPledgesByUserId";
import { getPlugins } from "./getPlugins";
import { getlanguage } from "./getlanguage";
import { getUserTag } from "./getUserTag";
import { getUserTagAncestors } from "./getUserTagAncestors";
import { me } from "./me";
import { myLanguage } from "./myLanguage";
import { organizations } from "./organizations";
Expand Down Expand Up @@ -84,6 +86,8 @@ export const Query: QueryResolvers = {
getNoteById,
getlanguage,
getPlugins,
getUserTag,
getUserTagAncestors,
isSampleOrganization,
me,
myLanguage,
Expand Down
4 changes: 2 additions & 2 deletions src/typeDefs/inputs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -490,8 +490,8 @@ export const inputs = gql`
}
input UpdateUserTagInput {
_id: ID!
tagColor: String!
tagId: ID!
tagColor: String
name: String!
}
Expand Down
4 changes: 4 additions & 0 deletions src/typeDefs/queries.ts
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,10 @@ export const queries = gql`
getNoteById(id: ID!): Note!
getUserTag(id: ID!): UserTag
getUserTagAncestors(id: ID!): [UserTag]
getAllNotesForAgendaItem(agendaItemId: ID!): [Note]
advertisementsConnection(
Expand Down
3 changes: 2 additions & 1 deletion src/typeDefs/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -742,7 +742,7 @@ export const types = gql`
type UserTagsConnection {
edges: [UserTagsConnectionEdge!]!
pageInfo: DefaultConnectionPageInfo!
totalCount: PositiveInt
totalCount: Int
}
"""
Expand All @@ -759,6 +759,7 @@ export const types = gql`
type UsersConnection {
edges: [UsersConnectionEdge!]!
pageInfo: DefaultConnectionPageInfo!
totalCount: Int
}
"""
Expand Down
24 changes: 20 additions & 4 deletions src/types/generatedGraphQLTypes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2306,6 +2306,8 @@ export type Query = {
getNoteById: Note;
getPledgesByUserId?: Maybe<Array<Maybe<FundraisingCampaignPledge>>>;
getPlugins?: Maybe<Array<Maybe<Plugin>>>;
getUserTag?: Maybe<UserTag>;
getUserTagAncestors?: Maybe<Array<Maybe<UserTag>>>;
getVenueByOrgId?: Maybe<Array<Maybe<Venue>>>;
getlanguage?: Maybe<Array<Maybe<Translation>>>;
groupChatById?: Maybe<GroupChat>;
Expand Down Expand Up @@ -2521,6 +2523,16 @@ export type QueryGetPledgesByUserIdArgs = {
};


export type QueryGetUserTagArgs = {
id: Scalars['ID']['input'];
};


export type QueryGetUserTagAncestorsArgs = {
id: Scalars['ID']['input'];
};


export type QueryGetVenueByOrgIdArgs = {
first?: InputMaybe<Scalars['Int']['input']>;
orderBy?: InputMaybe<VenueOrderByInput>;
Expand Down Expand Up @@ -2908,9 +2920,9 @@ export type UpdateUserPasswordInput = {
};

export type UpdateUserTagInput = {
_id: Scalars['ID']['input'];
name: Scalars['String']['input'];
tagColor: Scalars['String']['input'];
tagColor?: InputMaybe<Scalars['String']['input']>;
tagId: Scalars['ID']['input'];
};

export type User = {
Expand Down Expand Up @@ -3084,7 +3096,7 @@ export type UserTagsConnection = {
__typename?: 'UserTagsConnection';
edges: Array<UserTagsConnectionEdge>;
pageInfo: DefaultConnectionPageInfo;
totalCount?: Maybe<Scalars['PositiveInt']['output']>;
totalCount?: Maybe<Scalars['Int']['output']>;
};

/** A default connection edge on the UserTag type for UserTagsConnection. */
Expand Down Expand Up @@ -3133,6 +3145,7 @@ export type UsersConnection = {
__typename?: 'UsersConnection';
edges: Array<UsersConnectionEdge>;
pageInfo: DefaultConnectionPageInfo;
totalCount?: Maybe<Scalars['Int']['output']>;
};

/** A default connection edge on the User type for UsersConnection. */
Expand Down Expand Up @@ -4600,6 +4613,8 @@ export type QueryResolvers<ContextType = any, ParentType extends ResolversParent
getNoteById?: Resolver<ResolversTypes['Note'], ParentType, ContextType, RequireFields<QueryGetNoteByIdArgs, 'id'>>;
getPledgesByUserId?: Resolver<Maybe<Array<Maybe<ResolversTypes['FundraisingCampaignPledge']>>>, ParentType, ContextType, RequireFields<QueryGetPledgesByUserIdArgs, 'userId'>>;
getPlugins?: Resolver<Maybe<Array<Maybe<ResolversTypes['Plugin']>>>, ParentType, ContextType>;
getUserTag?: Resolver<Maybe<ResolversTypes['UserTag']>, ParentType, ContextType, RequireFields<QueryGetUserTagArgs, 'id'>>;
getUserTagAncestors?: Resolver<Maybe<Array<Maybe<ResolversTypes['UserTag']>>>, ParentType, ContextType, RequireFields<QueryGetUserTagAncestorsArgs, 'id'>>;
getVenueByOrgId?: Resolver<Maybe<Array<Maybe<ResolversTypes['Venue']>>>, ParentType, ContextType, RequireFields<QueryGetVenueByOrgIdArgs, 'orgId'>>;
getlanguage?: Resolver<Maybe<Array<Maybe<ResolversTypes['Translation']>>>, ParentType, ContextType, RequireFields<QueryGetlanguageArgs, 'lang_code'>>;
groupChatById?: Resolver<Maybe<ResolversTypes['GroupChat']>, ParentType, ContextType, RequireFields<QueryGroupChatByIdArgs, 'id'>>;
Expand Down Expand Up @@ -4784,7 +4799,7 @@ export type UserTagResolvers<ContextType = any, ParentType extends ResolversPare
export type UserTagsConnectionResolvers<ContextType = any, ParentType extends ResolversParentTypes['UserTagsConnection'] = ResolversParentTypes['UserTagsConnection']> = {
edges?: Resolver<Array<ResolversTypes['UserTagsConnectionEdge']>, ParentType, ContextType>;
pageInfo?: Resolver<ResolversTypes['DefaultConnectionPageInfo'], ParentType, ContextType>;
totalCount?: Resolver<Maybe<ResolversTypes['PositiveInt']>, ParentType, ContextType>;
totalCount?: Resolver<Maybe<ResolversTypes['Int']>, ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};

Expand All @@ -4797,6 +4812,7 @@ export type UserTagsConnectionEdgeResolvers<ContextType = any, ParentType extend
export type UsersConnectionResolvers<ContextType = any, ParentType extends ResolversParentTypes['UsersConnection'] = ResolversParentTypes['UsersConnection']> = {
edges?: Resolver<Array<ResolversTypes['UsersConnectionEdge']>, ParentType, ContextType>;
pageInfo?: Resolver<ResolversTypes['DefaultConnectionPageInfo'], ParentType, ContextType>;
totalCount?: Resolver<Maybe<ResolversTypes['Int']>, ParentType, ContextType>;
__isTypeOf?: IsTypeOfResolverFn<ParentType, ContextType>;
};

Expand Down
Loading

0 comments on commit db3d2f5

Please sign in to comment.