aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEugene Sokolov <eug-vs@keemail.me>2020-06-28 19:01:52 +0300
committerGitHub <noreply@github.com>2020-06-28 19:01:52 +0300
commit88e97a42096c1e4de7b9f1d8fefa0829bbc0d321 (patch)
treeae402f77d0d0d7b8d06dcefc614bbb9aad12ed59
parent8baf96be5ea7880cebe3aeda733b9196950be434 (diff)
parent29197dd3bc7e941707979b6c226e5f3b1a4cbbed (diff)
downloadwhich-api-88e97a42096c1e4de7b9f1d8fefa0829bbc0d321.tar.gz
Merge pull request #16 from which-ecosystem/feedback
Feedback endpoint & schema updates
-rw-r--r--hooks/convertPoll.ts43
-rw-r--r--hooks/signAuthority.ts8
-rw-r--r--models/feedback/feedback.model.ts7
-rw-r--r--models/feedback/feedback.schema.ts28
-rw-r--r--models/votes/vote.model.ts2
-rw-r--r--models/votes/vote.schema.ts6
-rw-r--r--package-lock.json6
-rw-r--r--package.json2
-rw-r--r--populateDb.ts18
-rw-r--r--services/feed/feed.hooks.ts4
-rw-r--r--services/feedback/feedback.hooks.ts9
-rw-r--r--services/feedback/feedback.service.ts13
-rw-r--r--services/index.ts2
-rw-r--r--services/polls/polls.hooks.ts43
-rw-r--r--services/votes/votes.hooks.ts10
15 files changed, 137 insertions, 64 deletions
diff --git a/hooks/convertPoll.ts b/hooks/convertPoll.ts
deleted file mode 100644
index 5e6f9f4..0000000
--- a/hooks/convertPoll.ts
+++ /dev/null
@@ -1,43 +0,0 @@
-import { HookContext } from '@feathersjs/feathers';
-import { Types } from 'mongoose';
-import bluebird from 'bluebird';
-import _ from 'lodash';
-import { Poll } from 'which-types';
-
-import { PollSchema } from '../models/polls/poll.schema';
-import VoteModel from '../models/votes/vote.model';
-
-
-export default async (context: HookContext): Promise<HookContext> => {
- const { app, result, params: { user } } = context;
-
- const convert = async (poll: PollSchema): Promise<Poll | null> => {
- const author = await app.service('users').get(poll.authorId);
-
- const contents = await VoteModel.aggregate([
- { $match: { pollId: Types.ObjectId(poll._id) } },
- { $group: { _id: '$which', total: { $sum: 1 } } }
- ]).then(groups => groups.reduce(
- (acc, group) => _.set(acc, `${group._id}.votes`, group.total),
- { left: { votes: 0 }, right: { votes: 0 } }
- ));
-
- const userChoice = await VoteModel.findOne(
- { pollId: poll._id, userId: user?._id }
- ).then(vote => vote?.which);
-
- return _.merge(
- _.omit(poll, ['authorId']),
- { author, contents, userChoice }
- );
- };
-
- if (Array.isArray(result)) {
- const polls = await bluebird.map(result, (poll: PollSchema) => convert(poll));
- context.result = _.compact(polls);
- } else {
- context.result = await convert(result);
- }
- return context;
-};
-
diff --git a/hooks/signAuthority.ts b/hooks/signAuthority.ts
new file mode 100644
index 0000000..b4d74b8
--- /dev/null
+++ b/hooks/signAuthority.ts
@@ -0,0 +1,8 @@
+import { HookContext } from '@feathersjs/feathers';
+
+export default async (context: HookContext): Promise<HookContext> => {
+ const { params: { user } } = context;
+ context.data.authorId = user._id;
+ return context;
+};
+
diff --git a/models/feedback/feedback.model.ts b/models/feedback/feedback.model.ts
new file mode 100644
index 0000000..b21747b
--- /dev/null
+++ b/models/feedback/feedback.model.ts
@@ -0,0 +1,7 @@
+import { Model, model } from 'mongoose';
+import { FeedbackSchema, feedbackSchema } from './feedback.schema';
+
+feedbackSchema.index({ version: 1, authorId: 1 }, { unique: true }); // Unique together
+
+export default model<FeedbackSchema, Model<FeedbackSchema>>('Feedback', feedbackSchema);
+
diff --git a/models/feedback/feedback.schema.ts b/models/feedback/feedback.schema.ts
new file mode 100644
index 0000000..ea6f6e7
--- /dev/null
+++ b/models/feedback/feedback.schema.ts
@@ -0,0 +1,28 @@
+import { Document, Schema, Types } from 'mongoose';
+
+export interface FeedbackSchema extends Document {
+ contents: string;
+ authorId: string;
+ score: number;
+ version: string;
+ createdAt: Date;
+}
+
+export const feedbackSchema = new Schema({
+ contents: String,
+ authorId: {
+ type: Types.ObjectId,
+ required: true,
+ ref: 'User'
+ },
+ score: {
+ type: Number,
+ required: true
+ },
+ version: {
+ type: String,
+ match: /^v\d+\.\d+\.\d+$/,
+ required: true
+ }
+}, { timestamps: true });
+
diff --git a/models/votes/vote.model.ts b/models/votes/vote.model.ts
index df2307e..bf2dcf6 100644
--- a/models/votes/vote.model.ts
+++ b/models/votes/vote.model.ts
@@ -1,7 +1,7 @@
import { Model, model } from 'mongoose';
import { VoteSchema, voteSchema } from './vote.schema';
-voteSchema.index({ pollId: 1, userId: 1 }, { unique: true }); // Unique together
+voteSchema.index({ pollId: 1, authorId: 1 }, { unique: true }); // Unique together
export default model<VoteSchema, Model<VoteSchema>>('Vote', voteSchema);
diff --git a/models/votes/vote.schema.ts b/models/votes/vote.schema.ts
index 63ba212..72b196d 100644
--- a/models/votes/vote.schema.ts
+++ b/models/votes/vote.schema.ts
@@ -1,12 +1,10 @@
import { Document, Schema, Types } from 'mongoose';
import { Vote } from 'which-types';
-export interface VoteSchema extends Document, Omit<Vote, '_id'> {
- password: string;
-}
+export interface VoteSchema extends Document, Omit<Vote, '_id'> {}
export const voteSchema = new Schema({
- userId: {
+ authorId: {
type: Types.ObjectId,
ref: 'user',
required: true
diff --git a/package-lock.json b/package-lock.json
index c0621bf..255fef5 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -3093,9 +3093,9 @@
}
},
"which-types": {
- "version": "1.4.2",
- "resolved": "https://registry.npmjs.org/which-types/-/which-types-1.4.2.tgz",
- "integrity": "sha512-nwcohvhH+VEA11cReLi/BgeuKHJYH7VM2BWe9OIX89CB+iaZ0+wb6oLFcIP6Vp6jw3k93yoPMe9pMBsOi4kj6w=="
+ "version": "1.6.1",
+ "resolved": "https://registry.npmjs.org/which-types/-/which-types-1.6.1.tgz",
+ "integrity": "sha512-uTCrp6+rbU48kyT9Z6upVo9CgGmiR50zFSwzDik8slE8oZ+0FC9SBEfJlfgADX/rFJVbIe8Vxsw4BsSxlL5Lsw=="
},
"word-wrap": {
"version": "1.2.3",
diff --git a/package.json b/package.json
index c55255c..3c3342d 100644
--- a/package.json
+++ b/package.json
@@ -33,7 +33,7 @@
"mongoose": "^5.9.18",
"ts-node": "^8.10.2",
"typescript": "^3.9.5",
- "which-types": "^1.4.2"
+ "which-types": "^1.6.1"
},
"repository": {
"type": "git",
diff --git a/populateDb.ts b/populateDb.ts
index b3e46af..e25005d 100644
--- a/populateDb.ts
+++ b/populateDb.ts
@@ -1,7 +1,12 @@
import mongoose from 'mongoose';
import bluebird from 'bluebird';
import _ from 'lodash';
-import { User, Poll, Vote } from 'which-types';
+import {
+ User,
+ Poll,
+ Vote,
+ Feedback
+} from 'which-types';
import app from './app';
@@ -71,6 +76,13 @@ const createVote = (userId: string, pollId: string): Promise<Vote> => {
}, { user: { _id: userId }, authenticated: true });
};
+const createFeedback = (userId: string): Promise<Feedback> => {
+ return app.service('feedback').create({
+ version: 'v1.0.0',
+ score: _.sample([1, 2, 3, 4, 5]),
+ content: 'Absolutely amazing!'
+ }, { user: { _id: userId }, authenticated: true });
+};
const populate = async () => {
const users = await bluebird.map(names, name => createUser(name));
@@ -81,6 +93,10 @@ const populate = async () => {
});
await bluebird.map(users, user => {
+ return createFeedback(user?._id || '');
+ });
+
+ await bluebird.map(users, user => {
const pollsToVote = _.sampleSize(polls, _.random(0, POLLS_AMOUNT));
return bluebird.map(pollsToVote, poll => createVote(user?._id || '', poll?._id || ''));
});
diff --git a/services/feed/feed.hooks.ts b/services/feed/feed.hooks.ts
index 54f6d61..6bff8dc 100644
--- a/services/feed/feed.hooks.ts
+++ b/services/feed/feed.hooks.ts
@@ -7,7 +7,7 @@ const raiseNewVerifedPolls = async (context: HookContext): Promise<HookContext>
// Raise unseen verified polls to the very top
context.result = _.sortBy(
context.result,
- poll => !(poll.author.verified && !poll.userChoice)
+ poll => !(poll.author.verified && !poll.vote)
);
return context;
};
@@ -16,7 +16,7 @@ const lowerOldPolls = async (context: HookContext): Promise<HookContext> => {
// Move all seen polls down
context.result = _.sortBy(
context.result,
- poll => !!poll.userChoice
+ poll => !!poll.vote
);
return context;
};
diff --git a/services/feedback/feedback.hooks.ts b/services/feedback/feedback.hooks.ts
new file mode 100644
index 0000000..56e9000
--- /dev/null
+++ b/services/feedback/feedback.hooks.ts
@@ -0,0 +1,9 @@
+import requireAuth from '../../hooks/requireAuth';
+import signAuthority from '../../hooks/signAuthority';
+
+export default {
+ before: {
+ create: [requireAuth, signAuthority]
+ }
+};
+
diff --git a/services/feedback/feedback.service.ts b/services/feedback/feedback.service.ts
new file mode 100644
index 0000000..a15ede9
--- /dev/null
+++ b/services/feedback/feedback.service.ts
@@ -0,0 +1,13 @@
+import { Application } from '@feathersjs/express';
+import service from 'feathers-mongoose';
+import Model from '../../models/feedback/feedback.model';
+
+import hooks from './feedback.hooks';
+
+const FeebackService = service({ Model });
+
+export default (app: Application): void => {
+ app.use('/feedback', FeebackService);
+ app.service('feedback').hooks(hooks);
+};
+
diff --git a/services/index.ts b/services/index.ts
index 1763a17..e5ea703 100644
--- a/services/index.ts
+++ b/services/index.ts
@@ -5,6 +5,7 @@ import Profiles from './profiles/profiles.service';
import Votes from './votes/votes.service';
import Auth from './auth/auth.service';
import Feed from './feed/feed.service';
+import Feedback from './feedback/feedback.service';
import tryAuthenticate from '../hooks/tryAuthenticate';
import logging from '../hooks/logging';
@@ -17,6 +18,7 @@ export default (app: Application): void => {
app.configure(Profiles);
app.configure(Votes);
app.configure(Feed);
+ app.configure(Feedback);
app.hooks({
before: {
diff --git a/services/polls/polls.hooks.ts b/services/polls/polls.hooks.ts
index 77fcc7a..9f2183f 100644
--- a/services/polls/polls.hooks.ts
+++ b/services/polls/polls.hooks.ts
@@ -1,6 +1,47 @@
-import convertPoll from '../../hooks/convertPoll';
+import { HookContext } from '@feathersjs/feathers';
+import { Types } from 'mongoose';
+import bluebird from 'bluebird'; import _ from 'lodash';
+import { Poll } from 'which-types';
+
+import { PollSchema } from '../../models/polls/poll.schema';
+import VoteModel from '../../models/votes/vote.model';
import sortByDate from '../../hooks/sortByDate';
+
+const convertPoll = async (context: HookContext): Promise<HookContext> => {
+ const { app, result, params: { user } } = context;
+
+ const convert = async (poll: PollSchema): Promise<Poll | null> => {
+ const author = await app.service('users').get(poll.authorId);
+
+ const contents = await VoteModel.aggregate([
+ { $match: { pollId: Types.ObjectId(poll._id) } },
+ { $group: { _id: '$which', total: { $sum: 1 } } }
+ ]).then(groups => groups.reduce(
+ (acc, group) => _.set(acc, `${group._id}.votes`, group.total),
+ { left: { votes: 0 }, right: { votes: 0 } }
+ ));
+
+ const vote = await VoteModel.findOne(
+ { pollId: poll._id, authorId: user?._id }
+ );
+
+ return _.merge(
+ _.omit(poll, ['authorId']),
+ { author, contents, vote }
+ );
+ };
+
+ if (Array.isArray(result)) {
+ const polls = await bluebird.map(result, (poll: PollSchema) => convert(poll));
+ context.result = _.compact(polls);
+ } else {
+ context.result = await convert(result);
+ }
+ return context;
+};
+
+
export default {
before: {
find: sortByDate
diff --git a/services/votes/votes.hooks.ts b/services/votes/votes.hooks.ts
index 7d0b3ba..56e9000 100644
--- a/services/votes/votes.hooks.ts
+++ b/services/votes/votes.hooks.ts
@@ -1,15 +1,9 @@
-import { HookContext } from '@feathersjs/feathers';
import requireAuth from '../../hooks/requireAuth';
-
-const addUserId = async (context: HookContext): Promise<HookContext> => {
- const { params: { user } } = context;
- context.data.userId = user._id;
- return context;
-};
+import signAuthority from '../../hooks/signAuthority';
export default {
before: {
- create: [requireAuth, addUserId]
+ create: [requireAuth, signAuthority]
}
};