Skip to content

Commit 0afe8f1

Browse files
authored
Merge pull request #8 from which-ecosystem/votes
Votes
2 parents e488591 + 64f5f8c commit 0afe8f1

21 files changed

+210
-84
lines changed

app.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import feathers from '@feathersjs/feathers';
22
import express from '@feathersjs/express';
33
import socketio from '@feathersjs/socketio';
4-
import configuration from '@feathersjs/configuration'
4+
import configuration from '@feathersjs/configuration';
55
import '@feathersjs/transport-commons';
66
import cors from 'cors';
77

config/default.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@
88
"local"
99
],
1010
"local": {
11-
"usernameField": "name",
11+
"usernameField": "username",
1212
"passwordField": "password"
1313
}
1414
}

hooks/convertPoll.ts

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import { HookContext } from '@feathersjs/feathers';
2+
import { Types } from 'mongoose';
3+
import bluebird from 'bluebird';
4+
import _ from 'lodash';
5+
import { Poll, User, Vote } from 'which-types';
6+
7+
import { PollSchema } from '../models/polls/poll.schema';
8+
import VoteModel from '../models/votes/vote.model';
9+
10+
11+
export default async (context: HookContext): Promise<HookContext> => {
12+
const { app, result, params: { user } } = context;
13+
14+
const convert = async (poll: PollSchema): Promise<Poll | null> => {
15+
const author = await app.service('users').get(poll.authorId);
16+
17+
const contents = await VoteModel.aggregate([
18+
{ $match: { pollId: Types.ObjectId(poll._id) } },
19+
{ $group: { _id: '$which', total: { $sum: 1 } } }
20+
]).then(groups => groups.reduce(
21+
(acc, group) => _.set(acc, group._id + '.votes', group.total),
22+
{ left: { votes: 0 }, right: { votes: 0 } }
23+
));
24+
25+
const userChoice = await VoteModel.findOne(
26+
{ pollId: poll._id, userId: user?._id }
27+
).then(vote => vote?.which);
28+
29+
return _.merge(
30+
_.omit(poll, ['authorId']),
31+
{ author, contents, userChoice }
32+
);
33+
};
34+
35+
if (Array.isArray(result)) {
36+
const polls = await bluebird.map(result, (poll: PollSchema) => convert(poll));
37+
context.result = _.compact(polls);
38+
} else {
39+
context.result = await convert(result);
40+
}
41+
return context;
42+
};
43+

hooks/expandAuthor.ts

Lines changed: 0 additions & 32 deletions
This file was deleted.

hooks/requireAuth.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { HookContext } from '@feathersjs/feathers';
2+
3+
export default async (context: HookContext): Promise<HookContext> => {
4+
if (!context.params.user) throw new Error('This endpoint requires auth!');
5+
return context;
6+
};
7+

hooks/tryAuthenticate.ts

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { HookContext } from '@feathersjs/feathers';
2+
import { authenticate } from '@feathersjs/authentication';
3+
4+
5+
export default async (context: HookContext): Promise<HookContext> => {
6+
return authenticate('jwt')(context).catch(() => context);
7+
};
8+

models/polls/poll.model.ts

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,20 @@
11
import { Model, model } from 'mongoose';
22
import { PollSchema, pollSchema } from './poll.schema';
3+
import { Types } from 'mongoose';
4+
import { Which } from 'which-types';
5+
6+
pollSchema.methods.vote = function(userId: string, which: Which): PollSchema {
7+
const participants: Types.ObjectId[] = ['left', 'right'].reduce((acc, option) => {
8+
const { votes } = this.contents[option];
9+
return acc.concat(votes);
10+
}, []);
11+
12+
if (!participants.some(user => user.equals(userId))) {
13+
this.contents[which].votes.push(userId);
14+
}
15+
16+
return this.save();
17+
}
318

419
export default model<PollSchema, Model<PollSchema>>('Poll', pollSchema);
520

models/polls/poll.schema.ts

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,21 @@
11
import { Document, Schema, Types } from 'mongoose';
2-
import { User } from '../users/user.schema';
32

4-
export interface ImageData {
3+
export interface ImageDataSchema {
54
url: string;
6-
votes: number;
75
}
86

9-
export interface Poll {
10-
author: User;
7+
export interface PollSchema extends Document {
118
contents: {
12-
left: ImageData;
13-
right: ImageData;
9+
left: ImageDataSchema;
10+
right: ImageDataSchema;
1411
};
15-
}
16-
17-
export interface PollSchema extends Document, Omit<Poll, 'author'> {
12+
createdAt: Date;
1813
authorId: string;
14+
vote: (userId: string, which: 'left' | 'right') => PollSchema;
1915
}
2016

21-
22-
const imageDataSchema = {
17+
export const imageDataSchema = {
2318
url: String,
24-
votes: Number
2519
};
2620

2721
export const pollSchema = new Schema({
@@ -33,5 +27,5 @@ export const pollSchema = new Schema({
3327
type: Types.ObjectId,
3428
ref: 'User'
3529
}
36-
});
30+
}, { timestamps: true });
3731

models/users/user.schema.ts

Lines changed: 7 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,21 @@
11
import { Document, Schema } from 'mongoose';
2+
import { User } from 'which-types';
23

3-
export interface User {
4-
name: string;
5-
avatarUrl?: string;
6-
age?: number;
7-
}
8-
9-
export interface UserSchema extends Document, User {
4+
export interface UserSchema extends Document, Omit<User, '_id'> {
105
password: string;
116
}
127

138
export const userSchema = new Schema({
14-
name: String,
9+
username: String,
1510
password: String,
11+
email: String,
1612
avatarUrl: {
1713
type: String,
1814
required: false
1915
},
2016
age: {
21-
type: Number
17+
type: Number,
18+
required: false
2219
}
23-
});
20+
}, { timestamps: true });
2421

models/votes/vote.model.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { Model, model } from 'mongoose';
2+
import { VoteSchema, voteSchema } from './vote.schema';
3+
4+
voteSchema.index({ pollId: 1, userId: 1 }, { unique: true }); // Unique together
5+
6+
export default model<VoteSchema, Model<VoteSchema>>('Vote', voteSchema);
7+

0 commit comments

Comments
 (0)