Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "hawk.api",
"version": "1.1.30",
"version": "1.1.31",
"main": "index.ts",
"license": "UNLICENSED",
"scripts": {
Expand Down
113 changes: 97 additions & 16 deletions src/models/eventsFactory.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ const Factory = require('./modelFactory');
const mongo = require('../mongo');
const Event = require('../models/event');
const { ObjectID } = require('mongodb');
const { composeFullRepetitionEvent } = require('../utils/merge');

/**
* @typedef {Object} RecentEventSchema
Expand Down Expand Up @@ -393,21 +394,43 @@ class EventsFactory extends Factory {
*
* @param {string|ObjectID} eventId - Event's id
* @param {Number} limit - count limitations
* @param {Number} skip - selection offset
* @param {Number} cursor - cursor for pagination
*
* @return {EventRepetitionSchema[]}
*
* @todo move to Repetitions(?) model
*/
async getEventRepetitions(eventId, limit = 10, skip = 0) {
async getEventRepetitions(repetitionId, limit = 10, cursor = undefined) {
limit = this.validateLimit(limit);
skip = this.validateSkip(skip);
cursor = cursor ? new ObjectID(cursor) : undefined;

const result = {
repetitions: [],
cursor: undefined,
};

/**
* Get original event
* @type {EventSchema}
*/
const eventOriginal = await this.findById(eventId);
let eventOriginal = await this.findById(repetitionId);

/**
* If original event is not found, it can mean that client is trying to get repetitions of original event
*/
if (!eventOriginal) {
const repetition = await this.getEventRepetition(repetitionId);

if (!repetition) {
return result;
}

eventOriginal = await this.findById(repetition.eventId);
}

if (!eventOriginal) {
return result;
}

/**
* Collect repetitions
Expand All @@ -416,13 +439,27 @@ class EventsFactory extends Factory {
const repetitions = await this.getCollection(this.TYPES.REPETITIONS)
.find({
groupHash: eventOriginal.groupHash,
_id: cursor ? { $lte: cursor } : {},
})
.sort({ _id: -1 })
.limit(limit)
.skip(skip)
.limit(limit + 1)
.toArray();

const isLastPortion = repetitions.length < limit && skip === 0;
if (repetitions.length === limit + 1) {
result.cursor = repetitions.pop()._id;
}

for (const repetition of repetitions) {
result.repetitions.push({
...eventOriginal,
_id: repetition._id,
payload: composeFullRepetitionEvent(eventOriginal, repetition).payload,
timestamp: repetition.timestamp,
firstAppearanceTimestamp: eventOriginal.timestamp,
});
}

const isLastPortion = repetitions.length < limit;

/**
* For last portion:
Expand All @@ -434,16 +471,14 @@ class EventsFactory extends Factory {
* @type {EventRepetitionSchema}
*/
const firstRepetition = {
_id: eventOriginal._id,
payload: eventOriginal.payload,
groupHash: eventOriginal.groupHash,
timestamp: eventOriginal.timestamp,
...eventOriginal,
firstAppearanceTimestamp: eventOriginal.timestamp,
};

repetitions.push(firstRepetition);
result.repetitions.push(firstRepetition);
}

return repetitions;
return result;
}

/**
Expand All @@ -455,10 +490,40 @@ class EventsFactory extends Factory {
* @todo move to Repetitions(?) model
*/
async getEventRepetition(repetitionId) {
return this.getCollection(this.TYPES.REPETITIONS)
const repetition = await this.getCollection(this.TYPES.REPETITIONS)
.findOne({
_id: ObjectID(repetitionId),
});

if (!repetition) {
/**
* If repetition is not found, it can mean that client is trying to get original event
*/
const event = await this.findById(repetitionId);

if (!event) {
return null;
}

return {
...event,
firstAppearanceTimestamp: event.timestamp,
};
}

const originalEvent = await this.findById(repetition.eventId);

if (!originalEvent) {
return null;
}

return {
...originalEvent,
_id: repetition._id,
payload: composeFullRepetitionEvent(originalEvent, repetition).payload,
timestamp: repetition.timestamp,
firstAppearanceTimestamp: originalEvent.timestamp,
};
}

/**
Expand Down Expand Up @@ -501,7 +566,15 @@ class EventsFactory extends Factory {
*
* @return {Promise<void>}
*/
async visitEvent(eventId, userId) {
async visitEvent(repetitionId, userId) {
const repetition = await this.getCollection(this.TYPES.REPETITIONS)
.findOne({ _id: new ObjectID(repetitionId) });

/**
* If repetition is not found, it can mean that client is trying to work with original event
*/
const eventId = repetition ? repetition.eventId : repetitionId;

return this.getCollection(this.TYPES.EVENTS)
.updateOne(
{ _id: new ObjectID(eventId) },
Expand All @@ -517,7 +590,15 @@ class EventsFactory extends Factory {
*
* @return {Promise<void>}
*/
async toggleEventMark(eventId, mark) {
async toggleEventMark(repetitionId, mark) {
const repetition = await this.getCollection(this.TYPES.REPETITIONS)
.findOne({ _id: new ObjectID(repetitionId) });

/**
* If repetition is not found, it can mean that client is trying to work with original event
*/
const eventId = repetition ? repetition.eventId : repetitionId;

const collection = this.getCollection(this.TYPES.EVENTS);
const query = { _id: new ObjectID(eventId) };

Expand Down
4 changes: 2 additions & 2 deletions src/resolvers/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const {
const user = require('./user').default;
const workspace = require('./workspace');
const project = require('./project');
const event = require('./event');
const repetition = require('./repetition');
const plans = require('./plans').default;
const projectNotifications = require('./projectNotifications').default;
const projectPatterns = require('./projectPatterns').default;
Expand Down Expand Up @@ -70,7 +70,7 @@ const resolvers = [
user,
workspace,
project,
event,
repetition,
projectNotifications,
projectPatterns,
userNotifications,
Expand Down
22 changes: 12 additions & 10 deletions src/resolvers/project.js
Original file line number Diff line number Diff line change
Expand Up @@ -280,24 +280,26 @@ module.exports = {
},

/**
* Find project's event
* Find project's repetition
*
* @param {ProjectDBScheme} project - result of parent resolver
* @param {String} eventId - event's identifier
* @param {String} repetitionId - repetition's identifier
*
* @returns {Event}
* @returns {Repetition}
*/
async event(project, { id: eventId }) {
async repetition(project, { id: repetitionId }) {
const factory = new EventsFactory(project._id);
const event = await factory.findById(eventId);

if (!event) {
return null;
}
const repetition = await factory.getEventRepetition(repetitionId);

event.projectId = project._id;
/**
* If repetition is not found, it can mean that client is trying to get original event
*/
if (!repetition) {
return factory.getEventLastRepetition(repetitionId);
}

return event;
return repetition;
},

/**
Expand Down
44 changes: 13 additions & 31 deletions src/resolvers/event.js → src/resolvers/repetition.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ const { ObjectID } = require('mongodb');
const sendPersonalNotification = require('../utils/personalNotifications').default;

/**
* See all types and fields here {@see ../typeDefs/event.graphql}
* See all types and fields here {@see ../typeDefs/repetition.graphql}
*/
module.exports = {
EventMarks: {
RepetitionMarks: {
starred(marks) {
return 'starred' in marks;
},
Expand All @@ -17,40 +17,22 @@ module.exports = {
return 'resolved' in marks;
},
},
Event: {
Repetition: {
/**
* Returns Event with concrete repetition
*
* @param {string} eventId - id of Event of which repetition requested
* @param {string} projectId - projectId of Event of which repetition requested
* @param {string|null} [repetitionId] - if not specified, last repetition will returned
* @return {Promise<EventRepetitionSchema>}
*/
async repetition({ id: eventId, projectId }, { id: repetitionId }) {
const factory = new EventsFactory(projectId);

if (!repetitionId) {
return factory.getEventLastRepetition(eventId);
}

return factory.getEventRepetition(repetitionId);
},

/**
* Returns repetitions list of the event
* Returns repetitions list of the repetition
*
* @param {ResolverObj} _obj
* @param {String} eventId
* @param {String} repetitionId
* @param {String} projectId
* @param {Number} limit
* @param {Number} skip
*
* @return {EventRepetitionSchema[]}
*/
async repetitions({ _id: eventId, projectId }, { limit, skip }) {
async repetitions({ _id: repetitionId, projectId }, { limit, cursor }) {
const factory = new EventsFactory(projectId);

return factory.getEventRepetitions(eventId, limit, skip);
return factory.getEventRepetitions(repetitionId, limit, cursor);
},

/**
Expand Down Expand Up @@ -124,15 +106,15 @@ module.exports = {
},
Mutation: {
/**
* Mark event as visited for current user
* Mark repetition as visited for current user
*
* @param {ResolverObj} _obj - resolver context
* @param {string} project - project id
* @param {string} id - event id
* @param {UserInContext} user - user context
* @return {Promise<boolean>}
*/
async visitEvent(_obj, { project, id }, { user }) {
async visitRepetition(_obj, { project, id }, { user }) {
const factory = new EventsFactory(project);

const { result } = await factory.visitEvent(id, user.id);
Expand All @@ -149,10 +131,10 @@ module.exports = {
* @param {string} mark - mark to set
* @return {Promise<boolean>}
*/
async toggleEventMark(_obj, { project, eventId, mark }) {
async toggleRepetitionMark(_obj, { project, repetitionId, mark }) {
const factory = new EventsFactory(project);

const { result } = await factory.toggleEventMark(eventId, mark);
const { result } = await factory.toggleEventMark(repetitionId, mark);

return !!result.ok;
},
Expand All @@ -162,9 +144,9 @@ module.exports = {
*
* @return {Function()}
*/
events: () => ({}),
repetitions: () => ({}),
},
EventsMutations: {
RepetitionMutations: {
/**
* Update assignee to selected event
*
Expand Down
4 changes: 2 additions & 2 deletions src/typeDefs/index.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { gql } from 'apollo-server-express';

import billing from './billing';
import event from './event';
import repetition from './repetition';
import notifications from './notifications';
import notificationsInput from './notificationsInput';
import projectNotifications from './projectNotifications';
Expand Down Expand Up @@ -87,7 +87,7 @@ const rootSchema = gql`
const typeDefinitions = [
rootSchema,
billing,
event,
repetition,
notifications,
notificationsInput,
projectNotifications,
Expand Down
6 changes: 3 additions & 3 deletions src/typeDefs/project.ts
Original file line number Diff line number Diff line change
Expand Up @@ -94,9 +94,9 @@ type Project {
uidAdded: User!

"""
Project's Event
Project repetitions
"""
event(id: ID!): Event
repetition: Repetition!

"""
Project events
Expand All @@ -107,7 +107,7 @@ type Project {

"Certain number of documents to skip"
skip: Int = 0
): [Event!]
): [Repetition!]

"""
Returns recent events grouped by day
Expand Down
Loading