From f4c4f2d4789880c0cfc956d08aab10b5a93ebcb1 Mon Sep 17 00:00:00 2001 From: ilyayudovin Date: Sun, 21 Jun 2020 13:10:05 +0300 Subject: feat: change votes type --- hooks/expandAuthor.ts | 21 +++++++++++++++++---- models/polls/poll.schema.ts | 17 +++++++++++++---- populateDb.ts | 17 ++++++++++------- 3 files changed, 40 insertions(+), 15 deletions(-) diff --git a/hooks/expandAuthor.ts b/hooks/expandAuthor.ts index 3b3e3df..5993839 100644 --- a/hooks/expandAuthor.ts +++ b/hooks/expandAuthor.ts @@ -6,12 +6,25 @@ import { Poll, PollSchema } from '../models/polls/poll.schema'; import { User } from '../models/users/user.schema'; import UserModel from '../models/users/user.model'; -const expandAuthor = async (poll: PollSchema): Promise => { +const convertPoll = async (poll: PollSchema): Promise => { return UserModel.findById(poll.authorId) .lean() .exec() .then((author: User | null): Poll | null => { - return author && _.merge(_.omit(poll, 'authorId'), { author }); + return author && { + _id: poll._id, + author, + contents: { + left: { + url: poll.contents.left.url, + votes: poll.contents.left.votes.length + }, + right: { + url: poll.contents.right.url, + votes: poll.contents.right.votes.length + } + } + }; }) .catch(err => { console.error(err); @@ -20,12 +33,12 @@ const expandAuthor = async (poll: PollSchema): Promise => { }; export const expandAuthorHook = async (context: HookContext): Promise => { - context.result = await expandAuthor(context.result); + context.result = await convertPoll(context.result); return context; }; export const expandAuthorManyHook = async (context: HookContext): Promise => { - const polls = await bluebird.map(context.result, (poll: PollSchema) => expandAuthor(poll)); + const polls = await bluebird.map(context.result, (poll: PollSchema) => convertPoll(poll)); context.result = _.compact(polls); return context; }; diff --git a/models/polls/poll.schema.ts b/models/polls/poll.schema.ts index bc6d497..236011f 100644 --- a/models/polls/poll.schema.ts +++ b/models/polls/poll.schema.ts @@ -7,6 +7,7 @@ export interface ImageData { } export interface Poll { + _id: string; author: User; contents: { left: ImageData; @@ -14,14 +15,22 @@ export interface Poll { }; } -export interface PollSchema extends Document, Omit { - authorId: string; +export interface ImageDataSchema { + url: string; + votes: string[]; } +export interface PollSchema extends Document { + contents: { + left: ImageDataSchema; + right: ImageDataSchema; + }; + authorId: string; +} -const imageDataSchema = { +export const imageDataSchema = { url: String, - votes: Number + votes: [Types.ObjectId] }; export const pollSchema = new Schema({ diff --git a/populateDb.ts b/populateDb.ts index a21b669..ae42d86 100644 --- a/populateDb.ts +++ b/populateDb.ts @@ -3,7 +3,7 @@ import bluebird from 'bluebird'; import _ from 'lodash'; import app from './app'; import { UserSchema } from './models/users/user.schema'; -import { PollSchema, ImageData } from './models/polls/poll.schema'; +import { PollSchema, ImageDataSchema } from './models/polls/poll.schema'; mongoose.connect('mongodb://localhost:27017/which', { useNewUrlParser: true }); @@ -28,12 +28,10 @@ const names: string[] = [ 'William' ]; -const generateImageData = (): ImageData => ({ - url: _.sample(imageUrls) || '', - votes: Math.floor(Math.random() * 101) -}); -const createPoll = (authorId: string): Promise => { + +const createPoll = (authorId: string, generateImageData:()=> ImageDataSchema): Promise => { + return app.service('polls').create({ contents: { left: generateImageData(), @@ -55,9 +53,14 @@ const createUser = (name: string): Promise => { const populate = async () => { const users = await bluebird.map(names, name => createUser(name)); + const generateImageData = (): ImageDataSchema => ({ + url: _.sample(imageUrls) || '', + votes: _.sampleSize(users.map(user => user._id), Math.floor(Math.random() * users.length)) + }); + await bluebird.mapSeries(new Array(POLLS_AMOUNT), async () => { const sampleUser = _.sample(users); - return createPoll(sampleUser?._id); + return createPoll(sampleUser?._id,generateImageData); }); }; -- cgit v1.2.3 From e99b51895afd532a529744396ecae87d47c68503 Mon Sep 17 00:00:00 2001 From: eug-vs Date: Sun, 21 Jun 2020 14:29:59 +0300 Subject: feat: change hooks and install which-types --- app.ts | 2 +- hooks/convertPoll.ts | 45 +++++++++++++++++++++++++++++++++++++ hooks/expandAuthor.ts | 45 ------------------------------------- models/polls/poll.schema.ts | 15 ------------- models/users/user.schema.ts | 7 +----- package-lock.json | 5 +++++ package.json | 3 ++- populateDb.ts | 4 +--- services/auth/auth.service.ts | 2 +- services/polls/polls.hooks.ts | 10 ++++----- services/profiles/profiles.hooks.ts | 6 ++--- 11 files changed, 64 insertions(+), 80 deletions(-) create mode 100644 hooks/convertPoll.ts delete mode 100644 hooks/expandAuthor.ts diff --git a/app.ts b/app.ts index 0623ef3..4d699fb 100644 --- a/app.ts +++ b/app.ts @@ -1,7 +1,7 @@ import feathers from '@feathersjs/feathers'; import express from '@feathersjs/express'; import socketio from '@feathersjs/socketio'; -import configuration from '@feathersjs/configuration' +import configuration from '@feathersjs/configuration'; import '@feathersjs/transport-commons'; import cors from 'cors'; diff --git a/hooks/convertPoll.ts b/hooks/convertPoll.ts new file mode 100644 index 0000000..62ddea1 --- /dev/null +++ b/hooks/convertPoll.ts @@ -0,0 +1,45 @@ +import { HookContext } from '@feathersjs/feathers'; +import bluebird from 'bluebird'; +import _ from 'lodash'; +import { Poll, User } from 'which-types'; + +import { PollSchema } from '../models/polls/poll.schema'; +import UserModel from '../models/users/user.model'; + +const convertPoll = async (poll: PollSchema): Promise => { + return UserModel.findById(poll.authorId) + .lean() + .exec() + .then((author: User | null): Poll | null => { + return author && _.merge( + _.omit(poll, ['authorId']), + { + author, + contents: { + left: { + votes: poll.contents.left.votes.length + }, + right: { + votes: poll.contents.right.votes.length + } + } + } + ); + }) + .catch(err => { + console.error(err); + return err; + }); +}; + +export const convertPollHook = async (context: HookContext): Promise => { + context.result = await convertPoll(context.result); + return context; +}; + +export const convertPollManyHook = async (context: HookContext): Promise => { + const polls = await bluebird.map(context.result, (poll: PollSchema) => convertPoll(poll)); + context.result = _.compact(polls); + return context; +}; + diff --git a/hooks/expandAuthor.ts b/hooks/expandAuthor.ts deleted file mode 100644 index 5993839..0000000 --- a/hooks/expandAuthor.ts +++ /dev/null @@ -1,45 +0,0 @@ -import { HookContext } from '@feathersjs/feathers'; -import bluebird from 'bluebird'; -import _ from 'lodash'; - -import { Poll, PollSchema } from '../models/polls/poll.schema'; -import { User } from '../models/users/user.schema'; -import UserModel from '../models/users/user.model'; - -const convertPoll = async (poll: PollSchema): Promise => { - return UserModel.findById(poll.authorId) - .lean() - .exec() - .then((author: User | null): Poll | null => { - return author && { - _id: poll._id, - author, - contents: { - left: { - url: poll.contents.left.url, - votes: poll.contents.left.votes.length - }, - right: { - url: poll.contents.right.url, - votes: poll.contents.right.votes.length - } - } - }; - }) - .catch(err => { - console.error(err); - return err; - }); -}; - -export const expandAuthorHook = async (context: HookContext): Promise => { - context.result = await convertPoll(context.result); - return context; -}; - -export const expandAuthorManyHook = async (context: HookContext): Promise => { - const polls = await bluebird.map(context.result, (poll: PollSchema) => convertPoll(poll)); - context.result = _.compact(polls); - return context; -}; - diff --git a/models/polls/poll.schema.ts b/models/polls/poll.schema.ts index 236011f..fd6751c 100644 --- a/models/polls/poll.schema.ts +++ b/models/polls/poll.schema.ts @@ -1,19 +1,4 @@ import { Document, Schema, Types } from 'mongoose'; -import { User } from '../users/user.schema'; - -export interface ImageData { - url: string; - votes: number; -} - -export interface Poll { - _id: string; - author: User; - contents: { - left: ImageData; - right: ImageData; - }; -} export interface ImageDataSchema { url: string; diff --git a/models/users/user.schema.ts b/models/users/user.schema.ts index fd7d1e1..9030d61 100644 --- a/models/users/user.schema.ts +++ b/models/users/user.schema.ts @@ -1,10 +1,5 @@ import { Document, Schema } from 'mongoose'; - -export interface User { - name: string; - avatarUrl?: string; - age?: number; -} +import { User } from 'which-types'; export interface UserSchema extends Document, User { password: string; diff --git a/package-lock.json b/package-lock.json index 771797b..6f78e7c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3050,6 +3050,11 @@ "isexe": "^2.0.0" } }, + "which-types": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/which-types/-/which-types-1.0.3.tgz", + "integrity": "sha512-anON+pR6+GeT+aCRhxK0Vj3AQvo6COSOG1zPy24VDxXnxluCvK5tNmlV+1Oe771lOjl0z3LEvc1B7YL5xYtFqQ==" + }, "word-wrap": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz", diff --git a/package.json b/package.json index 7116faa..7b27466 100644 --- a/package.json +++ b/package.json @@ -21,7 +21,8 @@ "cors": "^2.8.5", "feathers-mongoose": "^8.3.0", "lodash": "^4.17.15", - "mongoose": "^5.9.18" + "mongoose": "^5.9.18", + "which-types": "^1.0.3" }, "repository": { "type": "git", diff --git a/populateDb.ts b/populateDb.ts index ae42d86..a666427 100644 --- a/populateDb.ts +++ b/populateDb.ts @@ -29,9 +29,7 @@ const names: string[] = [ ]; - const createPoll = (authorId: string, generateImageData:()=> ImageDataSchema): Promise => { - return app.service('polls').create({ contents: { left: generateImageData(), @@ -60,7 +58,7 @@ const populate = async () => { await bluebird.mapSeries(new Array(POLLS_AMOUNT), async () => { const sampleUser = _.sample(users); - return createPoll(sampleUser?._id,generateImageData); + return createPoll(sampleUser?._id, generateImageData); }); }; diff --git a/services/auth/auth.service.ts b/services/auth/auth.service.ts index 42846b0..826357c 100644 --- a/services/auth/auth.service.ts +++ b/services/auth/auth.service.ts @@ -1,6 +1,6 @@ import { AuthenticationService, - JWTStrategy + JWTStrategy } from '@feathersjs/authentication'; import { LocalStrategy } from '@feathersjs/authentication-local'; import { Application } from '@feathersjs/express'; diff --git a/services/polls/polls.hooks.ts b/services/polls/polls.hooks.ts index 0637320..a914cd0 100644 --- a/services/polls/polls.hooks.ts +++ b/services/polls/polls.hooks.ts @@ -1,12 +1,12 @@ import { - expandAuthorHook, - expandAuthorManyHook -} from '../../hooks/expandAuthor'; + convertPollHook, + convertPollManyHook +} from '../../hooks/convertPoll'; export default { after: { - get: [expandAuthorHook], - find: [expandAuthorManyHook] + get: [convertPollHook], + find: [convertPollManyHook] } }; diff --git a/services/profiles/profiles.hooks.ts b/services/profiles/profiles.hooks.ts index bb05d94..4447bee 100644 --- a/services/profiles/profiles.hooks.ts +++ b/services/profiles/profiles.hooks.ts @@ -1,10 +1,10 @@ import { - expandAuthorManyHook -} from '../../hooks/expandAuthor'; + convertPollManyHook +} from '../../hooks/convertPoll'; export default { after: { - get: [expandAuthorManyHook] + get: [convertPollManyHook] } }; -- cgit v1.2.3 From 4909dda29566710793b8445ab4426102ca4a0324 Mon Sep 17 00:00:00 2001 From: eug-vs Date: Mon, 22 Jun 2020 01:42:43 +0300 Subject: feat: create Votes service --- services/index.ts | 2 ++ services/votes/votes.class.ts | 14 ++++++++++++++ services/votes/votes.hooks.ts | 15 +++++++++++++++ services/votes/votes.service.ts | 10 ++++++++++ 4 files changed, 41 insertions(+) create mode 100644 services/votes/votes.class.ts create mode 100644 services/votes/votes.hooks.ts create mode 100644 services/votes/votes.service.ts diff --git a/services/index.ts b/services/index.ts index f000837..638fb7a 100644 --- a/services/index.ts +++ b/services/index.ts @@ -2,6 +2,7 @@ import { Application } from '@feathersjs/express'; import Users from './users/users.service'; import Polls from './polls/polls.service'; import Profiles from './profiles/profiles.service'; +import Votes from './votes/votes.service'; import Auth from './auth/auth.service'; export default (app: Application): void => { @@ -9,5 +10,6 @@ export default (app: Application): void => { app.configure(Users); app.configure(Polls); app.configure(Profiles); + app.configure(Votes); }; diff --git a/services/votes/votes.class.ts b/services/votes/votes.class.ts new file mode 100644 index 0000000..d95c148 --- /dev/null +++ b/services/votes/votes.class.ts @@ -0,0 +1,14 @@ +import PollModel from '../../models/polls/poll.model'; +import { PollSchema } from '../../models/polls/poll.schema'; + +export default class Votes { + async create(data: any, params: any): Promise { + return PollModel.findById(params.route.id) + .then(poll => poll?.vote(params.user._id, data.which)) + .catch(e => { + console.error(e); + return null; + }); + } +} + diff --git a/services/votes/votes.hooks.ts b/services/votes/votes.hooks.ts new file mode 100644 index 0000000..2e29008 --- /dev/null +++ b/services/votes/votes.hooks.ts @@ -0,0 +1,15 @@ +import { + convertPollHook +} from '../../hooks/convertPoll'; + +import { authenticate } from '@feathersjs/authentication'; + +export default { + before: { + create: [authenticate('jwt')] + }, + after: { + all: [convertPollHook] + } +}; + diff --git a/services/votes/votes.service.ts b/services/votes/votes.service.ts new file mode 100644 index 0000000..3947d9b --- /dev/null +++ b/services/votes/votes.service.ts @@ -0,0 +1,10 @@ +import { Application } from '@feathersjs/express'; +import Votes from './votes.class'; + +import hooks from './votes.hooks'; + +export default (app: Application): void => { + app.use('/polls/:id/votes/', new Votes()); + app.service('/polls/:id/votes/').hooks(hooks); +}; + -- cgit v1.2.3 From 1af98079d43b8bf5da7a32870b7bb60e5f59e554 Mon Sep 17 00:00:00 2001 From: eug-vs Date: Mon, 22 Jun 2020 01:47:12 +0300 Subject: feat: add vote function to schema --- models/polls/poll.model.ts | 5 +++++ models/polls/poll.schema.ts | 1 + 2 files changed, 6 insertions(+) diff --git a/models/polls/poll.model.ts b/models/polls/poll.model.ts index 7f6be9a..6f3d088 100644 --- a/models/polls/poll.model.ts +++ b/models/polls/poll.model.ts @@ -1,5 +1,10 @@ import { Model, model } from 'mongoose'; import { PollSchema, pollSchema } from './poll.schema'; +pollSchema.methods.vote = function(userId: string, which: 'left' | 'right'): PollSchema { + this.contents[which].votes.push(userId); + return this.save(); +} + export default model>('Poll', pollSchema); diff --git a/models/polls/poll.schema.ts b/models/polls/poll.schema.ts index fd6751c..0caa6b2 100644 --- a/models/polls/poll.schema.ts +++ b/models/polls/poll.schema.ts @@ -11,6 +11,7 @@ export interface PollSchema extends Document { right: ImageDataSchema; }; authorId: string; + vote: (userId: string, which: 'left' | 'right') => void; } export const imageDataSchema = { -- cgit v1.2.3 From ea35b242da316e75928a0a6d336378ea50f4d6f8 Mon Sep 17 00:00:00 2001 From: eug-vs Date: Mon, 22 Jun 2020 19:08:35 +0300 Subject: fix: protect password field in ALL calls --- services/users/users.hooks.ts | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/services/users/users.hooks.ts b/services/users/users.hooks.ts index fc17ed7..580d1d2 100644 --- a/services/users/users.hooks.ts +++ b/services/users/users.hooks.ts @@ -1,7 +1,14 @@ import { hooks } from '@feathersjs/authentication-local'; +import { HookContext } from '@feathersjs/feathers'; const hashPassword = hooks.hashPassword('password'); -const protectPassword = hooks.protect('password'); + +const protectPassword = async (context: HookContext): Promise => { + const { dispatch } = hooks.protect('password')(context); + context.result = dispatch; + context.dispatch = dispatch; + return context; +} export default { after: { -- cgit v1.2.3 From ef94c648b14bd09bf28b8f47ed015b319aa8f0cc Mon Sep 17 00:00:00 2001 From: eug-vs Date: Mon, 22 Jun 2020 21:09:14 +0300 Subject: fix: protect only local 'get' queries --- services/users/users.hooks.ts | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/services/users/users.hooks.ts b/services/users/users.hooks.ts index 580d1d2..8eecca3 100644 --- a/services/users/users.hooks.ts +++ b/services/users/users.hooks.ts @@ -3,16 +3,15 @@ import { HookContext } from '@feathersjs/feathers'; const hashPassword = hooks.hashPassword('password'); -const protectPassword = async (context: HookContext): Promise => { - const { dispatch } = hooks.protect('password')(context); - context.result = dispatch; - context.dispatch = dispatch; +const localDispatch = async (context: HookContext): Promise => { + context.result = context.dispatch; return context; } export default { after: { - all: [protectPassword] + all: [hooks.protect('password')], + get: [localDispatch] // Protect password from local get's }, before: { create: [hashPassword], -- cgit v1.2.3 From 967ee2225a874dc114079882d737a25a487404be Mon Sep 17 00:00:00 2001 From: eug-vs Date: Mon, 22 Jun 2020 21:11:19 +0300 Subject: refactor: improve vote endpoint --- services/votes/votes.class.ts | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/services/votes/votes.class.ts b/services/votes/votes.class.ts index d95c148..0490b7e 100644 --- a/services/votes/votes.class.ts +++ b/services/votes/votes.class.ts @@ -3,12 +3,14 @@ import { PollSchema } from '../../models/polls/poll.schema'; export default class Votes { async create(data: any, params: any): Promise { - return PollModel.findById(params.route.id) - .then(poll => poll?.vote(params.user._id, data.which)) - .catch(e => { - console.error(e); - return null; - }); + const poll = await PollModel.findById(params.route.id); + if (poll) { + const which: 'left' | 'right' = data.which; + const { user } = params; + poll.contents[which].votes.push(user._id); + return poll.save(); + } + return null; } } -- cgit v1.2.3 From 4101b4ff7a5c328164fe74ebfa3c42b82f332c43 Mon Sep 17 00:00:00 2001 From: eug-vs Date: Mon, 22 Jun 2020 21:12:07 +0300 Subject: fix: get rid of poll.vote function --- models/polls/poll.model.ts | 5 ----- 1 file changed, 5 deletions(-) diff --git a/models/polls/poll.model.ts b/models/polls/poll.model.ts index 6f3d088..7f6be9a 100644 --- a/models/polls/poll.model.ts +++ b/models/polls/poll.model.ts @@ -1,10 +1,5 @@ import { Model, model } from 'mongoose'; import { PollSchema, pollSchema } from './poll.schema'; -pollSchema.methods.vote = function(userId: string, which: 'left' | 'right'): PollSchema { - this.contents[which].votes.push(userId); - return this.save(); -} - export default model>('Poll', pollSchema); -- cgit v1.2.3 From 676c722a994a214c182bcf26b80eab09ebf9f61e Mon Sep 17 00:00:00 2001 From: eug-vs Date: Mon, 22 Jun 2020 21:29:17 +0300 Subject: refactor: unite convertPoll hooks --- hooks/convertPoll.ts | 59 +++++++++++++++++-------------------- services/polls/polls.hooks.ts | 8 ++--- services/profiles/profiles.hooks.ts | 6 ++-- services/votes/votes.hooks.ts | 7 ++--- 4 files changed, 33 insertions(+), 47 deletions(-) diff --git a/hooks/convertPoll.ts b/hooks/convertPoll.ts index 62ddea1..aacf3de 100644 --- a/hooks/convertPoll.ts +++ b/hooks/convertPoll.ts @@ -4,42 +4,37 @@ import _ from 'lodash'; import { Poll, User } from 'which-types'; import { PollSchema } from '../models/polls/poll.schema'; -import UserModel from '../models/users/user.model'; -const convertPoll = async (poll: PollSchema): Promise => { - return UserModel.findById(poll.authorId) - .lean() - .exec() - .then((author: User | null): Poll | null => { - return author && _.merge( - _.omit(poll, ['authorId']), - { - author, - contents: { - left: { - votes: poll.contents.left.votes.length - }, - right: { - votes: poll.contents.right.votes.length + +export default async (context: HookContext): Promise => { + const { app, result } = context; + + const convert = async (poll: PollSchema): Promise => { + return app.service('users').get(poll.authorId) + .then((author: User | null): Poll | null => { + return author && _.merge( + _.omit(poll, ['authorId']), + { + author, + contents: { + left: { + votes: poll.contents.left.votes.length + }, + right: { + votes: poll.contents.right.votes.length + } } } - } - ); - }) - .catch(err => { - console.error(err); - return err; - }); -}; - -export const convertPollHook = async (context: HookContext): Promise => { - context.result = await convertPoll(context.result); - return context; -}; + ); + }); + }; -export const convertPollManyHook = async (context: HookContext): Promise => { - const polls = await bluebird.map(context.result, (poll: PollSchema) => convertPoll(poll)); - context.result = _.compact(polls); + 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/services/polls/polls.hooks.ts b/services/polls/polls.hooks.ts index a914cd0..eba3e63 100644 --- a/services/polls/polls.hooks.ts +++ b/services/polls/polls.hooks.ts @@ -1,12 +1,8 @@ -import { - convertPollHook, - convertPollManyHook -} from '../../hooks/convertPoll'; +import convertPoll from '../../hooks/convertPoll'; export default { after: { - get: [convertPollHook], - find: [convertPollManyHook] + all: [convertPoll], } }; diff --git a/services/profiles/profiles.hooks.ts b/services/profiles/profiles.hooks.ts index 4447bee..13d6f63 100644 --- a/services/profiles/profiles.hooks.ts +++ b/services/profiles/profiles.hooks.ts @@ -1,10 +1,8 @@ -import { - convertPollManyHook -} from '../../hooks/convertPoll'; +import convertPoll from '../../hooks/convertPoll'; export default { after: { - get: [convertPollManyHook] + all: [convertPoll] } }; diff --git a/services/votes/votes.hooks.ts b/services/votes/votes.hooks.ts index 2e29008..a41b8a9 100644 --- a/services/votes/votes.hooks.ts +++ b/services/votes/votes.hooks.ts @@ -1,15 +1,12 @@ -import { - convertPollHook -} from '../../hooks/convertPoll'; - import { authenticate } from '@feathersjs/authentication'; +import convertPoll from '../../hooks/convertPoll'; export default { before: { create: [authenticate('jwt')] }, after: { - all: [convertPollHook] + all: [convertPoll] } }; -- cgit v1.2.3 From 5255b85532f2e2709b31e891a167c1a250a0aa7e Mon Sep 17 00:00:00 2001 From: eug-vs Date: Tue, 23 Jun 2020 02:33:10 +0300 Subject: fix: return object instead of document --- services/votes/votes.class.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/services/votes/votes.class.ts b/services/votes/votes.class.ts index 0490b7e..6b9181b 100644 --- a/services/votes/votes.class.ts +++ b/services/votes/votes.class.ts @@ -8,7 +8,8 @@ export default class Votes { const which: 'left' | 'right' = data.which; const { user } = params; poll.contents[which].votes.push(user._id); - return poll.save(); + poll.save(); + return poll.toObject(); } return null; } -- cgit v1.2.3 From dbfb0d30f0e5cd44ea188d72ceb05acac2ac40d7 Mon Sep 17 00:00:00 2001 From: eug-vs Date: Tue, 23 Jun 2020 22:50:59 +0300 Subject: feat: only allow voting once --- models/polls/poll.model.ts | 13 +++++++++++++ models/polls/poll.schema.ts | 2 +- services/votes/votes.class.ts | 7 ++----- 3 files changed, 16 insertions(+), 6 deletions(-) diff --git a/models/polls/poll.model.ts b/models/polls/poll.model.ts index 7f6be9a..ecd8ad8 100644 --- a/models/polls/poll.model.ts +++ b/models/polls/poll.model.ts @@ -1,5 +1,18 @@ import { Model, model } from 'mongoose'; import { PollSchema, pollSchema } from './poll.schema'; +pollSchema.methods.vote = function(userId: string, which: 'left' | 'right'): PollSchema { + const participants = ['left', 'right'].reduce((acc, option) => { + const { votes } = this.contents[option]; + return acc.concat(votes); + }, []); + + if (!participants.indexOf(userId) === -1) { + this.contents[which].votes.push(userId); + } + + return this.save(); +} + export default model>('Poll', pollSchema); diff --git a/models/polls/poll.schema.ts b/models/polls/poll.schema.ts index 0caa6b2..380c069 100644 --- a/models/polls/poll.schema.ts +++ b/models/polls/poll.schema.ts @@ -11,7 +11,7 @@ export interface PollSchema extends Document { right: ImageDataSchema; }; authorId: string; - vote: (userId: string, which: 'left' | 'right') => void; + vote: (userId: string, which: 'left' | 'right') => PollSchema; } export const imageDataSchema = { diff --git a/services/votes/votes.class.ts b/services/votes/votes.class.ts index 6b9181b..3220ee7 100644 --- a/services/votes/votes.class.ts +++ b/services/votes/votes.class.ts @@ -5,11 +5,8 @@ export default class Votes { async create(data: any, params: any): Promise { const poll = await PollModel.findById(params.route.id); if (poll) { - const which: 'left' | 'right' = data.which; - const { user } = params; - poll.contents[which].votes.push(user._id); - poll.save(); - return poll.toObject(); + const updatedPoll = await poll.vote(params.user._id, data.which); + return updatedPoll.toObject(); } return null; } -- cgit v1.2.3 From b054bd6cf5be0eed0c17fbacec8bcc09cf013d44 Mon Sep 17 00:00:00 2001 From: eug-vs Date: Tue, 23 Jun 2020 23:59:31 +0300 Subject: fix: check user correctly --- models/polls/poll.model.ts | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/models/polls/poll.model.ts b/models/polls/poll.model.ts index ecd8ad8..11d0cfa 100644 --- a/models/polls/poll.model.ts +++ b/models/polls/poll.model.ts @@ -1,13 +1,14 @@ import { Model, model } from 'mongoose'; import { PollSchema, pollSchema } from './poll.schema'; +import { Types } from 'mongoose'; pollSchema.methods.vote = function(userId: string, which: 'left' | 'right'): PollSchema { - const participants = ['left', 'right'].reduce((acc, option) => { + const participants: Types.ObjectId[] = ['left', 'right'].reduce((acc, option) => { const { votes } = this.contents[option]; return acc.concat(votes); }, []); - if (!participants.indexOf(userId) === -1) { + if (!participants.some(user => user.equals(userId))) { this.contents[which].votes.push(userId); } -- cgit v1.2.3 From 75e527334e4e9a94b63704f87aa650c75f13891c Mon Sep 17 00:00:00 2001 From: eug-vs Date: Wed, 24 Jun 2020 00:58:45 +0300 Subject: feat: migrate to latest which-types --- config/default.json | 2 +- models/polls/poll.model.ts | 3 ++- models/polls/poll.schema.ts | 3 ++- models/users/user.schema.ts | 10 ++++++---- package-lock.json | 7 ++++--- package.json | 6 +++--- populateDb.ts | 4 ++-- 7 files changed, 20 insertions(+), 15 deletions(-) diff --git a/config/default.json b/config/default.json index e112f3e..3d8ffd2 100644 --- a/config/default.json +++ b/config/default.json @@ -8,7 +8,7 @@ "local" ], "local": { - "usernameField": "name", + "usernameField": "username", "passwordField": "password" } } diff --git a/models/polls/poll.model.ts b/models/polls/poll.model.ts index 11d0cfa..6749e5c 100644 --- a/models/polls/poll.model.ts +++ b/models/polls/poll.model.ts @@ -1,8 +1,9 @@ import { Model, model } from 'mongoose'; import { PollSchema, pollSchema } from './poll.schema'; import { Types } from 'mongoose'; +import { Which } from 'which-types'; -pollSchema.methods.vote = function(userId: string, which: 'left' | 'right'): PollSchema { +pollSchema.methods.vote = function(userId: string, which: Which): PollSchema { const participants: Types.ObjectId[] = ['left', 'right'].reduce((acc, option) => { const { votes } = this.contents[option]; return acc.concat(votes); diff --git a/models/polls/poll.schema.ts b/models/polls/poll.schema.ts index 380c069..d495e4b 100644 --- a/models/polls/poll.schema.ts +++ b/models/polls/poll.schema.ts @@ -10,6 +10,7 @@ export interface PollSchema extends Document { left: ImageDataSchema; right: ImageDataSchema; }; + createdAt: Date; authorId: string; vote: (userId: string, which: 'left' | 'right') => PollSchema; } @@ -28,5 +29,5 @@ export const pollSchema = new Schema({ type: Types.ObjectId, ref: 'User' } -}); +}, { timestamps: true }); diff --git a/models/users/user.schema.ts b/models/users/user.schema.ts index 9030d61..ff6cbe9 100644 --- a/models/users/user.schema.ts +++ b/models/users/user.schema.ts @@ -1,19 +1,21 @@ import { Document, Schema } from 'mongoose'; import { User } from 'which-types'; -export interface UserSchema extends Document, User { +export interface UserSchema extends Document, Omit { password: string; } export const userSchema = new Schema({ - name: String, + username: String, password: String, + email: String, avatarUrl: { type: String, required: false }, age: { - type: Number + type: Number, + required: false } -}); +}, { timestamps: true }); diff --git a/package-lock.json b/package-lock.json index 6f78e7c..51ac1a5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3051,9 +3051,10 @@ } }, "which-types": { - "version": "1.0.3", - "resolved": "https://registry.npmjs.org/which-types/-/which-types-1.0.3.tgz", - "integrity": "sha512-anON+pR6+GeT+aCRhxK0Vj3AQvo6COSOG1zPy24VDxXnxluCvK5tNmlV+1Oe771lOjl0z3LEvc1B7YL5xYtFqQ==" + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which-types/-/which-types-1.3.1.tgz", + "integrity": "sha512-UU7+/FRfELIrUyZiTJkTDJ9dNxhW/ZVcWTjXn9TMtaqdIEDtu+NDFe13jZkFhlPVsVwwXa5R4n6MUa1iuLhAlg==", + "dev": true }, "word-wrap": { "version": "1.2.3", diff --git a/package.json b/package.json index 7b27466..3986b6c 100644 --- a/package.json +++ b/package.json @@ -21,8 +21,7 @@ "cors": "^2.8.5", "feathers-mongoose": "^8.3.0", "lodash": "^4.17.15", - "mongoose": "^5.9.18", - "which-types": "^1.0.3" + "mongoose": "^5.9.18" }, "repository": { "type": "git", @@ -43,6 +42,7 @@ "eslint": "^7.2.0", "eslint-config-airbnb-typescript": "^8.0.2", "eslint-plugin-import": "^2.21.2", - "typescript": "^3.9.5" + "typescript": "^3.9.5", + "which-types": "^1.3.1" } } diff --git a/populateDb.ts b/populateDb.ts index a666427..1a3b016 100644 --- a/populateDb.ts +++ b/populateDb.ts @@ -39,11 +39,11 @@ const createPoll = (authorId: string, generateImageData:()=> ImageDataSchema): P }); }; -const createUser = (name: string): Promise => { +const createUser = (username: string): Promise => { return app.service('users').create({ avatarUrl: _.sample(imageUrls) || '', password: 'supersecret', - name + username }); }; -- cgit v1.2.3 From ffcb9d248228087ee05c7569784705b41d729aee Mon Sep 17 00:00:00 2001 From: eug-vs Date: Thu, 25 Jun 2020 08:56:47 +0300 Subject: feat: create vote model --- models/polls/poll.schema.ts | 7 ++++++- models/votes/vote.model.ts | 5 +++++ models/votes/vote.schema.ts | 22 ++++++++++++++++++++++ package-lock.json | 6 +++--- package.json | 2 +- 5 files changed, 37 insertions(+), 5 deletions(-) create mode 100644 models/votes/vote.model.ts create mode 100644 models/votes/vote.schema.ts diff --git a/models/polls/poll.schema.ts b/models/polls/poll.schema.ts index d495e4b..2f39aa1 100644 --- a/models/polls/poll.schema.ts +++ b/models/polls/poll.schema.ts @@ -17,7 +17,12 @@ export interface PollSchema extends Document { export const imageDataSchema = { url: String, - votes: [Types.ObjectId] + votes: [ + { + type: Types.ObjectId, + ref: 'vote' + } + ] }; export const pollSchema = new Schema({ diff --git a/models/votes/vote.model.ts b/models/votes/vote.model.ts new file mode 100644 index 0000000..1dbb146 --- /dev/null +++ b/models/votes/vote.model.ts @@ -0,0 +1,5 @@ +import { Model, model } from 'mongoose'; +import { VoteSchema, voteSchema } from './vote.schema'; + +export default model>('Vote', voteSchema); + diff --git a/models/votes/vote.schema.ts b/models/votes/vote.schema.ts new file mode 100644 index 0000000..36b38f2 --- /dev/null +++ b/models/votes/vote.schema.ts @@ -0,0 +1,22 @@ +import { Document, Schema, Types } from 'mongoose'; +import { Vote } from 'which-types'; + +export interface VoteSchema extends Document, Omit { + password: string; +} + +export const voteSchema = new Schema({ + userId: { + type: Types.ObjectId, + ref: 'user' + }, + pollId: { + type: Types.ObjectId, + ref: 'poll' + }, + which: { + type: String, + match: /left|right/g + } +}, { timestamps: true }); + diff --git a/package-lock.json b/package-lock.json index 51ac1a5..1402c27 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3051,9 +3051,9 @@ } }, "which-types": { - "version": "1.3.1", - "resolved": "https://registry.npmjs.org/which-types/-/which-types-1.3.1.tgz", - "integrity": "sha512-UU7+/FRfELIrUyZiTJkTDJ9dNxhW/ZVcWTjXn9TMtaqdIEDtu+NDFe13jZkFhlPVsVwwXa5R4n6MUa1iuLhAlg==", + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/which-types/-/which-types-1.4.0.tgz", + "integrity": "sha512-dq5f7AmZeataiQZxko+Dw1xRvWdzSXTwXrjKxtyL5zqLgS29J1PXjTgcAWMfbkZhbd8+iJLkfxKvYZ42itmxeA==", "dev": true }, "word-wrap": { diff --git a/package.json b/package.json index 3986b6c..ecdd31d 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,6 @@ "eslint-config-airbnb-typescript": "^8.0.2", "eslint-plugin-import": "^2.21.2", "typescript": "^3.9.5", - "which-types": "^1.3.1" + "which-types": "^1.4.0" } } -- cgit v1.2.3 From fc9cf3b8f77e9068fa51d614b0d0b120f7bf2440 Mon Sep 17 00:00:00 2001 From: eug-vs Date: Thu, 25 Jun 2020 09:03:46 +0300 Subject: feat!: construct VoteService based on VoteModel --- models/polls/poll.schema.ts | 7 ------- services/votes/votes.class.ts | 14 -------------- services/votes/votes.service.ts | 9 ++++++--- 3 files changed, 6 insertions(+), 24 deletions(-) delete mode 100644 services/votes/votes.class.ts diff --git a/models/polls/poll.schema.ts b/models/polls/poll.schema.ts index 2f39aa1..4d1d762 100644 --- a/models/polls/poll.schema.ts +++ b/models/polls/poll.schema.ts @@ -2,7 +2,6 @@ import { Document, Schema, Types } from 'mongoose'; export interface ImageDataSchema { url: string; - votes: string[]; } export interface PollSchema extends Document { @@ -17,12 +16,6 @@ export interface PollSchema extends Document { export const imageDataSchema = { url: String, - votes: [ - { - type: Types.ObjectId, - ref: 'vote' - } - ] }; export const pollSchema = new Schema({ diff --git a/services/votes/votes.class.ts b/services/votes/votes.class.ts deleted file mode 100644 index 3220ee7..0000000 --- a/services/votes/votes.class.ts +++ /dev/null @@ -1,14 +0,0 @@ -import PollModel from '../../models/polls/poll.model'; -import { PollSchema } from '../../models/polls/poll.schema'; - -export default class Votes { - async create(data: any, params: any): Promise { - const poll = await PollModel.findById(params.route.id); - if (poll) { - const updatedPoll = await poll.vote(params.user._id, data.which); - return updatedPoll.toObject(); - } - return null; - } -} - diff --git a/services/votes/votes.service.ts b/services/votes/votes.service.ts index 3947d9b..81f767c 100644 --- a/services/votes/votes.service.ts +++ b/services/votes/votes.service.ts @@ -1,10 +1,13 @@ import { Application } from '@feathersjs/express'; -import Votes from './votes.class'; +import service from 'feathers-mongoose'; +import Model from '../../models/votes/vote.model'; import hooks from './votes.hooks'; +const VoteService = service({ Model }); + export default (app: Application): void => { - app.use('/polls/:id/votes/', new Votes()); - app.service('/polls/:id/votes/').hooks(hooks); + app.use('/votes/', VoteService); + app.service('votes').hooks(hooks); }; -- cgit v1.2.3 From 2e28a2555119c8958737e84fd2312e9930046242 Mon Sep 17 00:00:00 2001 From: eug-vs Date: Thu, 25 Jun 2020 09:48:39 +0300 Subject: feat: change match to enum in voteSchema --- models/votes/vote.schema.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/models/votes/vote.schema.ts b/models/votes/vote.schema.ts index 36b38f2..709e8bf 100644 --- a/models/votes/vote.schema.ts +++ b/models/votes/vote.schema.ts @@ -16,7 +16,7 @@ export const voteSchema = new Schema({ }, which: { type: String, - match: /left|right/g + enum: ['left', 'right'] } }, { timestamps: true }); -- cgit v1.2.3 From edcd782cdbfd59d051752515ee6309faa3e1f103 Mon Sep 17 00:00:00 2001 From: eug-vs Date: Thu, 25 Jun 2020 09:50:28 +0300 Subject: feat: generate Votes in populateDB script --- populateDb.ts | 40 ++++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/populateDb.ts b/populateDb.ts index 1a3b016..719b7e7 100644 --- a/populateDb.ts +++ b/populateDb.ts @@ -1,13 +1,14 @@ import mongoose from 'mongoose'; import bluebird from 'bluebird'; import _ from 'lodash'; +import { User, Poll, Vote } from 'which-types'; + import app from './app'; -import { UserSchema } from './models/users/user.schema'; -import { PollSchema, ImageDataSchema } from './models/polls/poll.schema'; mongoose.connect('mongodb://localhost:27017/which', { useNewUrlParser: true }); const POLLS_AMOUNT = 20; +const VOTES_AMOUNT = 160; const imageUrls: string[] = [ // eslint-disable max-len @@ -28,8 +29,17 @@ const names: string[] = [ 'William' ]; +const choices = [ + 'left', + 'right' +]; + + +const createPoll = (authorId: string): Promise => { + const generateImageData = () => ({ + url: _.sample(imageUrls) || '', + }); -const createPoll = (authorId: string, generateImageData:()=> ImageDataSchema): Promise => { return app.service('polls').create({ contents: { left: generateImageData(), @@ -39,7 +49,7 @@ const createPoll = (authorId: string, generateImageData:()=> ImageDataSchema): P }); }; -const createUser = (username: string): Promise => { +const createUser = (username: string): Promise => { return app.service('users').create({ avatarUrl: _.sample(imageUrls) || '', password: 'supersecret', @@ -47,18 +57,28 @@ const createUser = (username: string): Promise => { }); }; +const createVote = (userId: string, pollId: string): Promise => { + return app.service('votes').create({ + userId, + pollId, + which: _.sample(choices) + }); +} + const populate = async () => { const users = await bluebird.map(names, name => createUser(name)); - const generateImageData = (): ImageDataSchema => ({ - url: _.sample(imageUrls) || '', - votes: _.sampleSize(users.map(user => user._id), Math.floor(Math.random() * users.length)) + const polls = await bluebird.mapSeries(new Array(POLLS_AMOUNT), async () => { + const user = _.sample(users); + return createPoll(user?._id || ''); + }); - await bluebird.mapSeries(new Array(POLLS_AMOUNT), async () => { - const sampleUser = _.sample(users); - return createPoll(sampleUser?._id, generateImageData); + const votes = await bluebird.mapSeries(new Array(VOTES_AMOUNT), async () => { + const user = _.sample(users); + const poll = _.sample(polls); + return createVote(user?._id || '', poll?._id || ''); }); }; -- cgit v1.2.3 From 34ec4c9f1bbd13a7a633bdd02425d207986baea3 Mon Sep 17 00:00:00 2001 From: eug-vs Date: Thu, 25 Jun 2020 10:39:32 +0300 Subject: feat: count votes by aggregate in convertPoll hook --- hooks/convertPoll.ts | 39 ++++++++++++++++++++------------------- 1 file changed, 20 insertions(+), 19 deletions(-) diff --git a/hooks/convertPoll.ts b/hooks/convertPoll.ts index aacf3de..b4f8376 100644 --- a/hooks/convertPoll.ts +++ b/hooks/convertPoll.ts @@ -1,32 +1,33 @@ import { HookContext } from '@feathersjs/feathers'; +import { Types } from 'mongoose'; import bluebird from 'bluebird'; import _ from 'lodash'; -import { Poll, User } from 'which-types'; +import { Poll, User, Vote } from 'which-types'; import { PollSchema } from '../models/polls/poll.schema'; +import VoteModel from '../models/votes/vote.model'; export default async (context: HookContext): Promise => { - const { app, result } = context; + const { app, result, params: { user } } = context; const convert = async (poll: PollSchema): Promise => { - return app.service('users').get(poll.authorId) - .then((author: User | null): Poll | null => { - return author && _.merge( - _.omit(poll, ['authorId']), - { - author, - contents: { - left: { - votes: poll.contents.left.votes.length - }, - right: { - votes: poll.contents.right.votes.length - } - } - } - ); - }); + 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), + {} + )); + + const userChoice = await VoteModel.findOne({ pollId: poll._id, userId: user?._id }); + + return _.merge( + _.omit(poll, ['authorId']), + { author, contents, userChoice } + ); }; if (Array.isArray(result)) { -- cgit v1.2.3 From 681e51a658bfed723b368fc5b71b1350909d9496 Mon Sep 17 00:00:00 2001 From: eug-vs Date: Thu, 25 Jun 2020 11:02:54 +0300 Subject: feat: setup hooks for VoteService --- services/votes/votes.hooks.ts | 13 ++++++++----- services/votes/votes.service.ts | 2 +- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/services/votes/votes.hooks.ts b/services/votes/votes.hooks.ts index a41b8a9..63f19e3 100644 --- a/services/votes/votes.hooks.ts +++ b/services/votes/votes.hooks.ts @@ -1,12 +1,15 @@ +import { HookContext } from '@feathersjs/feathers'; import { authenticate } from '@feathersjs/authentication'; -import convertPoll from '../../hooks/convertPoll'; + +const addUserId = async (context: HookContext): Promise => { + const { params: { user} } = context; + context.data.userId = user._id; + return context; +}; export default { before: { - create: [authenticate('jwt')] - }, - after: { - all: [convertPoll] + create: [authenticate('jwt'), addUserId] } }; diff --git a/services/votes/votes.service.ts b/services/votes/votes.service.ts index 81f767c..cb40c1a 100644 --- a/services/votes/votes.service.ts +++ b/services/votes/votes.service.ts @@ -7,7 +7,7 @@ import hooks from './votes.hooks'; const VoteService = service({ Model }); export default (app: Application): void => { - app.use('/votes/', VoteService); + app.use('/votes', VoteService); app.service('votes').hooks(hooks); }; -- cgit v1.2.3 From a58354a1d1bf967fc932723b9138d8c6322591d5 Mon Sep 17 00:00:00 2001 From: eug-vs Date: Thu, 25 Jun 2020 11:23:20 +0300 Subject: feat: validate fields in votes --- models/votes/vote.model.ts | 2 ++ models/votes/vote.schema.ts | 9 ++++++--- populateDb.ts | 12 ++++-------- 3 files changed, 12 insertions(+), 11 deletions(-) diff --git a/models/votes/vote.model.ts b/models/votes/vote.model.ts index 1dbb146..df2307e 100644 --- a/models/votes/vote.model.ts +++ b/models/votes/vote.model.ts @@ -1,5 +1,7 @@ import { Model, model } from 'mongoose'; import { VoteSchema, voteSchema } from './vote.schema'; +voteSchema.index({ pollId: 1, userId: 1 }, { unique: true }); // Unique together + export default model>('Vote', voteSchema); diff --git a/models/votes/vote.schema.ts b/models/votes/vote.schema.ts index 709e8bf..63ba212 100644 --- a/models/votes/vote.schema.ts +++ b/models/votes/vote.schema.ts @@ -8,15 +8,18 @@ export interface VoteSchema extends Document, Omit { export const voteSchema = new Schema({ userId: { type: Types.ObjectId, - ref: 'user' + ref: 'user', + required: true }, pollId: { type: Types.ObjectId, - ref: 'poll' + ref: 'poll', + required: true }, which: { type: String, - enum: ['left', 'right'] + enum: ['left', 'right'], + required: true } }, { timestamps: true }); diff --git a/populateDb.ts b/populateDb.ts index 719b7e7..757280a 100644 --- a/populateDb.ts +++ b/populateDb.ts @@ -8,7 +8,6 @@ import app from './app'; mongoose.connect('mongodb://localhost:27017/which', { useNewUrlParser: true }); const POLLS_AMOUNT = 20; -const VOTES_AMOUNT = 160; const imageUrls: string[] = [ // eslint-disable max-len @@ -59,10 +58,9 @@ const createUser = (username: string): Promise => { const createVote = (userId: string, pollId: string): Promise => { return app.service('votes').create({ - userId, pollId, which: _.sample(choices) - }); + }, { user: { _id: userId } }); } @@ -72,13 +70,11 @@ const populate = async () => { const polls = await bluebird.mapSeries(new Array(POLLS_AMOUNT), async () => { const user = _.sample(users); return createPoll(user?._id || ''); - }); - const votes = await bluebird.mapSeries(new Array(VOTES_AMOUNT), async () => { - const user = _.sample(users); - const poll = _.sample(polls); - return createVote(user?._id || '', poll?._id || ''); + const votes = await bluebird.map(users, user => { + const pollsToVote = _.sampleSize(polls, _.random(0, POLLS_AMOUNT)); + return bluebird.map(pollsToVote, poll => createVote(user?._id || '', poll?._id || '')); }); }; -- cgit v1.2.3 From cf34d891b349b8bb799393067a77fa23a4874ad5 Mon Sep 17 00:00:00 2001 From: eug-vs Date: Thu, 25 Jun 2020 11:25:16 +0300 Subject: fix: provide default value of 0 to votes amount --- hooks/convertPoll.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/hooks/convertPoll.ts b/hooks/convertPoll.ts index b4f8376..4da25c1 100644 --- a/hooks/convertPoll.ts +++ b/hooks/convertPoll.ts @@ -19,7 +19,7 @@ export default async (context: HookContext): Promise => { { $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 }); -- cgit v1.2.3 From a9678b794758164a86a8c136c1d8acc8b1d0135d Mon Sep 17 00:00:00 2001 From: eug-vs Date: Thu, 25 Jun 2020 11:53:21 +0300 Subject: fix: add userChoice correctly --- hooks/convertPoll.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/hooks/convertPoll.ts b/hooks/convertPoll.ts index 4da25c1..1c32851 100644 --- a/hooks/convertPoll.ts +++ b/hooks/convertPoll.ts @@ -22,7 +22,9 @@ export default async (context: HookContext): Promise => { { left: { votes: 0 }, right: { votes: 0 } } )); - const userChoice = await VoteModel.findOne({ pollId: poll._id, userId: user?._id }); + const userChoice = await VoteModel.findOne( + { pollId: poll._id, userId: user?._id } + ).then(vote => vote?.which); return _.merge( _.omit(poll, ['authorId']), -- cgit v1.2.3 From 64f5f8c3f9660f649dfdaad07d84aa8c26b9661e Mon Sep 17 00:00:00 2001 From: eug-vs Date: Thu, 25 Jun 2020 12:08:15 +0300 Subject: feat: setup global auth hooks --- hooks/requireAuth.ts | 7 +++++++ hooks/tryAuthenticate.ts | 8 ++++++++ services/index.ts | 8 ++++++++ services/votes/votes.hooks.ts | 4 ++-- 4 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 hooks/requireAuth.ts create mode 100644 hooks/tryAuthenticate.ts diff --git a/hooks/requireAuth.ts b/hooks/requireAuth.ts new file mode 100644 index 0000000..a7b0e96 --- /dev/null +++ b/hooks/requireAuth.ts @@ -0,0 +1,7 @@ +import { HookContext } from '@feathersjs/feathers'; + +export default async (context: HookContext): Promise => { + if (!context.params.user) throw new Error('This endpoint requires auth!'); + return context; +}; + diff --git a/hooks/tryAuthenticate.ts b/hooks/tryAuthenticate.ts new file mode 100644 index 0000000..e179417 --- /dev/null +++ b/hooks/tryAuthenticate.ts @@ -0,0 +1,8 @@ +import { HookContext } from '@feathersjs/feathers'; +import { authenticate } from '@feathersjs/authentication'; + + +export default async (context: HookContext): Promise => { + return authenticate('jwt')(context).catch(() => context); +}; + diff --git a/services/index.ts b/services/index.ts index 638fb7a..fe5ffdc 100644 --- a/services/index.ts +++ b/services/index.ts @@ -5,11 +5,19 @@ import Profiles from './profiles/profiles.service'; import Votes from './votes/votes.service'; import Auth from './auth/auth.service'; +import tryAuthenticate from '../hooks/tryAuthenticate'; + export default (app: Application): void => { app.configure(Auth); app.configure(Users); app.configure(Polls); app.configure(Profiles); app.configure(Votes); + + app.hooks({ + before: { + all: tryAuthenticate + } + }) }; diff --git a/services/votes/votes.hooks.ts b/services/votes/votes.hooks.ts index 63f19e3..1cf7261 100644 --- a/services/votes/votes.hooks.ts +++ b/services/votes/votes.hooks.ts @@ -1,5 +1,5 @@ import { HookContext } from '@feathersjs/feathers'; -import { authenticate } from '@feathersjs/authentication'; +import requireAuth from '../../hooks/requireAuth'; const addUserId = async (context: HookContext): Promise => { const { params: { user} } = context; @@ -9,7 +9,7 @@ const addUserId = async (context: HookContext): Promise => { export default { before: { - create: [authenticate('jwt'), addUserId] + create: [requireAuth, addUserId] } }; -- cgit v1.2.3