-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #40 from GTBitsOfGood/Keerthi/API
Custom event type, custom event, and custom graph type endpoints
- Loading branch information
Showing
26 changed files
with
519 additions
and
35 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
import { CustomEventType } from "@/src/utils/types"; | ||
import { dbConnect } from "@/src/utils/db-connect"; | ||
import CustomEventTypeModel from "@/src/models/custom-event-type"; | ||
import CustomEvent from "@/src/models/custom-event"; | ||
import CustomGraphType from "@/src/models/custom-graph-type"; | ||
import { Types } from "mongoose"; | ||
|
||
|
||
export const findEventForProject = async (projectId: string | Types.ObjectId, category: string, subcategory: string) => { | ||
await dbConnect(); | ||
return await CustomEventTypeModel.findOne({ projectId, category, subcategory }) | ||
|
||
} | ||
export const createCustomEventType = async (eventType: Partial<CustomEventType>) => { | ||
await dbConnect(); | ||
const createdEventType = await CustomEventTypeModel.create(eventType); | ||
return createdEventType; | ||
} | ||
|
||
export const getCustomEventTypesForProject = async (projectId: string) => { | ||
await dbConnect(); | ||
const eventTypes = await CustomEventTypeModel.find({ projectId }) | ||
return eventTypes; | ||
} | ||
export const getCustomEventType = async (projectId: string, category: string, subcategory: string) => { | ||
await dbConnect(); | ||
const eventType = await CustomEventTypeModel.find({ projectId, category, subcategory }) | ||
return eventType; | ||
} | ||
export const getCustomEventTypeID = async (projectId: string, category: string, subcategory: string) => { | ||
await dbConnect(); | ||
const eventType = await CustomEventTypeModel.findOne({ projectId, category, subcategory }) | ||
return eventType?._id; | ||
} | ||
export const deleteCustomEventType = async (projectId: string, category: string, subcategory: string) => { | ||
const deletedEventType = await CustomEventTypeModel.findOne({ projectId, category, subcategory }); | ||
if (!deletedEventType) { | ||
return; | ||
} | ||
let eventTypeId = deletedEventType._id | ||
|
||
await CustomEvent.deleteMany({ eventTypeId }) | ||
await CustomGraphType.deleteMany({ eventTypeId }) | ||
await CustomEventTypeModel.deleteOne({ projectId, category, subcategory }) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
import { CustomEventType } from "@/src/utils/types"; | ||
import { dbConnect } from "@/src/utils/db-connect"; | ||
import CustomEventTypeModel from "@/src/models/custom-event-type"; | ||
import CustomEvent from "@/src/models/custom-event"; | ||
import CustomGraphType from "@/src/models/custom-graph-type"; | ||
|
||
|
||
export const createCustomEvent = async (projectId: string, eventTypeId: string, properties: object) => { | ||
await dbConnect(); | ||
let eventType = await CustomEventTypeModel.findOne({ _id: eventTypeId, projectId }) | ||
|
||
if (!eventType) { | ||
return null; | ||
} | ||
let typeProperties = eventType.properties; | ||
if (Object.keys(typeProperties).length === Object.keys(properties).length | ||
&& Object.keys(typeProperties).every(k => properties.hasOwnProperty(k))) { | ||
return null; | ||
} | ||
const createdEvent = await CustomEvent.create({ projectId, eventTypeId, properties }); | ||
return createdEvent; | ||
} | ||
//one function to get eventTypeId, then this paginated method | ||
export const paginatedGetCustomEvents = async (eventTypeId: string, afterDate: Date, afterID: string, limit: number) => { | ||
await dbConnect(); | ||
const events = await CustomEvent.find( | ||
{ | ||
createdAt: { $gte: afterDate }, | ||
...(afterID && { _id: { $gte: afterID } }), | ||
eventTypeId | ||
}) | ||
.limit(limit); | ||
return events | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
import { dbConnect } from "@/src/utils/db-connect"; | ||
import CustomGraphTypeModel from "@/src/models/custom-event-type"; | ||
import { CustomGraphType, GraphTypes } from "@/src/utils/types"; | ||
import CustomEventTypeModel from "@/src/models/custom-event-type"; | ||
|
||
|
||
export const createCustomGraphType = async (newGraph: Partial<CustomGraphType>) => { | ||
await dbConnect(); | ||
let eventTypeId = newGraph.eventTypeId | ||
let eventType = await CustomEventTypeModel.findOne({ _id: eventTypeId }) | ||
if (!eventType) { | ||
return null; | ||
} | ||
let typeProperties = eventType.properties; | ||
if (!typeProperties.includes(newGraph.xProperty as string) || !typeProperties.includes(newGraph.yProperty as string)) { | ||
return null; | ||
} | ||
|
||
if (!Object.values(GraphTypes).includes(newGraph.graphType as GraphTypes)) { | ||
return null; | ||
} | ||
const createdGraphType = await CustomGraphTypeModel.create(newGraph); | ||
return createdGraphType; | ||
} | ||
|
||
export const getCustomGraphTypes = async (eventTypeId: string, projectId: string) => { | ||
await dbConnect(); | ||
const graphTypes = await CustomGraphTypeModel.find({ eventTypeId, projectId }) | ||
return graphTypes | ||
} | ||
export const deleteCustomGraphType = async (_id: string) => { | ||
await dbConnect(); | ||
const deletedGraphType = await CustomGraphTypeModel.deleteOne({ _id }) | ||
return deletedGraphType | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
import { createCustomEventType, getCustomEventTypesForProject, deleteCustomEventType, findEventForProject } from "@/src/actions/custom-event-type"; | ||
import { getProjectIDByName } from "@/src/actions/project"; | ||
import { getProjectByServerKey } from "@/src/actions/project"; | ||
import { relogRequestHandler } from "@/src/middleware/request-middleware"; | ||
import APIWrapper from "@/src/utils/api-wrapper"; | ||
import { CustomEventType } from "@/src/utils/types"; | ||
import { Request } from "express"; | ||
|
||
const customEventTypeRoute = APIWrapper({ | ||
POST: { | ||
config: { | ||
requireClientToken: false, | ||
requireServerToken: true | ||
}, | ||
handler: async (req: Request) => { | ||
const { category, subcategory, properties } = req.body; | ||
if (!category || !subcategory) { | ||
throw new Error("You must specify a category and subcategory to create a custom event type!") | ||
} | ||
const project = await getProjectByServerKey(req.headers.servertoken as string); | ||
|
||
if (!project) { | ||
throw new Error("Project does not exist for client token") | ||
} | ||
const customEventType: Partial<CustomEventType> = { | ||
category: category, | ||
subcategory: subcategory, | ||
properties: properties, | ||
projectId: project._id, | ||
} | ||
|
||
const preexistingEventType = await findEventForProject(project._id, category, subcategory) | ||
if (preexistingEventType != null) { | ||
throw new Error("A custom event type with the same category and subcategory already exists") | ||
} | ||
|
||
const createdType = await createCustomEventType(customEventType); | ||
return createdType; | ||
}, | ||
}, | ||
GET: { | ||
config: { | ||
requireClientToken: false, | ||
requireServerToken: false | ||
}, | ||
handler: async (req: Request) => { | ||
const projectName = req.query.projectName | ||
if (!projectName) { | ||
throw new Error("You must specify a project to get custom event types!") | ||
} | ||
const id = await getProjectIDByName(projectName as string); | ||
|
||
if (!id) { | ||
throw new Error("Project does not exist") | ||
} | ||
const types = await getCustomEventTypesForProject(id.toString()); | ||
return types; | ||
}, | ||
}, | ||
DELETE: { | ||
config: { | ||
requireClientToken: false, | ||
requireServerToken: true | ||
}, | ||
handler: async (req: Request) => { | ||
const { category, subcategory } = req.body | ||
if (!category || !subcategory) { | ||
throw new Error("You must specify a category and subcategory to delete custom event types!") | ||
} | ||
const project = await getProjectByServerKey(req.headers.servertoken as string); | ||
|
||
if (!project) { | ||
throw new Error("Project does not exist") | ||
} | ||
await deleteCustomEventType(project._id.toString(), category, subcategory) | ||
}, | ||
}, | ||
|
||
}); | ||
|
||
|
||
export const customEventType = relogRequestHandler(customEventTypeRoute); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
import { createCustomEvent, paginatedGetCustomEvents } from "@/src/actions/custom-event"; | ||
import { getCustomEventTypeID } from "@/src/actions/custom-event-type"; | ||
import { getProjectIDByName } from "@/src/actions/project"; | ||
import { getProjectByClientKey } from "@/src/actions/project"; | ||
import { relogRequestHandler } from "@/src/middleware/request-middleware"; | ||
import APIWrapper from "@/src/utils/api-wrapper"; | ||
import { CustomEvent } from "@/src/utils/types"; | ||
import { Request } from "express"; | ||
|
||
const customEventRoute = APIWrapper({ | ||
POST: { | ||
config: { | ||
requireClientToken: true, | ||
requireServerToken: false | ||
}, | ||
handler: async (req: Request) => { | ||
const { eventTypeId, properties } = req.body; | ||
if (!eventTypeId || !properties) { | ||
throw new Error("You must specify a category and subcategory to create a custom event!") | ||
} | ||
const project = await getProjectByClientKey(req.headers.clienttoken as string); | ||
|
||
if (!project) { | ||
throw new Error("Project does not exist for client token") | ||
} | ||
|
||
const createdEvent = await createCustomEvent(project._id.toString(), eventTypeId, properties); | ||
|
||
if (!createdEvent) { | ||
throw new Error("Failed to create custom event"); | ||
} | ||
return createdEvent; | ||
}, | ||
}, | ||
GET: { | ||
config: { | ||
requireClientToken: false, | ||
requireServerToken: false | ||
}, | ||
handler: async (req: Request) => { | ||
const { projectName, category, subcategory } = req.query | ||
if (!projectName) { | ||
throw new Error("You must specify a project to get custom event types!") | ||
} | ||
const id = await getProjectIDByName(projectName as string); | ||
|
||
if (!id) { | ||
throw new Error("Project does not exist") | ||
} | ||
const eventType = await getCustomEventTypeID(id.toString(), category as string, subcategory as string); | ||
if (!eventType) { | ||
throw new Error("Event type does not exist"); | ||
} | ||
|
||
const { afterId } = req.query; | ||
const limit = req.query.limit ?? 10 | ||
const afterTime = req.query.afterTime ? new Date(req.query.afterTime as string) : new Date(Date.now() - 60 * 60 * 24 * 30 * 1000) | ||
if (!projectName) { | ||
throw new Error("You must specify a project name to create a project!") | ||
} | ||
let events = await paginatedGetCustomEvents(eventType.toString(), afterTime, afterId as string, parseInt(limit as string)); | ||
return events; | ||
}, | ||
}, | ||
|
||
}); | ||
|
||
|
||
export const customEvent = relogRequestHandler(customEventRoute); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,3 +1,5 @@ | ||
export { clickEvent } from '@/src/controllers/events/click-event'; | ||
export { inputEvent } from '@/src/controllers/events/input-event'; | ||
export { visitEvent } from '@/src/controllers/events/visit-event'; | ||
export { visitEvent } from '@/src/controllers/events/visit-event'; | ||
export { customEventType } from '@/src/controllers/events/custom-event-type'; | ||
export { customEvent} from '@/src/controllers/events/custom-event'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -28,7 +28,6 @@ const visitEventRoute = APIWrapper({ | |
eventProperties: { | ||
pageUrl, | ||
userId, | ||
date | ||
} | ||
} | ||
|
||
|
Oops, something went wrong.