Skip to content

Commit

Permalink
Merge pull request #3 from foo-comments/reactions
Browse files Browse the repository at this point in the history
Reactions
  • Loading branch information
tigransimonyan authored Dec 17, 2023
2 parents 1a0d974 + 7e7973c commit 8c91526
Show file tree
Hide file tree
Showing 15 changed files with 198 additions and 5 deletions.
7 changes: 7 additions & 0 deletions .env.docker
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
MONGODB_URI=mongodb://mongo:27017/foo-comments
API_URL=http://localhost:9547/api
PORT=9547

ADMIN_EMAIL_ADDR=
BOT_EMAIL_ADDR=
BOT_EMAIL_PASS=
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -12,3 +12,5 @@ jsconfig.json
yarn.lock
.DS_Store
*package-lock.json

mongo-data
11 changes: 11 additions & 0 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
FROM node:18-alpine

WORKDIR /app

COPY ["package.json", "package-lock.json*", "./"]

RUN npm install --production

COPY . .

CMD ["node", "index.js"]
12 changes: 12 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
build:
docker build -t foo-comments-server .

up:
docker-compose up -d


down:
docker-compose down

dev:
docker-compose -f docker-compose.dev.yml up
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -31,3 +31,27 @@ $ npm run kill
```


## Docker

modify `.env.docker` to run with docker.

### run mongo with docker

```
make dev
```
### build the docker image
```
make build
```

### start/stop system
To start
```
make up
```

To stop
```
make down
```
11 changes: 11 additions & 0 deletions docker-compose.dev.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
version: '3.8'

services:

mongo:
image: mongo
restart: always
volumes:
- './mongo-data:/data/db'
ports:
- 27017:27017
18 changes: 18 additions & 0 deletions docker-compose.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
version: '3.8'

services:
mongo:
image: mongo
restart: always
volumes:
- './mongo-data:/data/db'

foo-comment-server:
image: foo-comments-server
restart: always
volumes:
- ./.env.docker:/app/.env:ro
ports:
- 9547:9547
depends_on:
- mongo
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@
"handlebars": "^4.7.6",
"handlebars-dateformat": "^1.1.1",
"moment": "^2.29.1",
"mongoose": "^5.10.11",
"mongoose": "^7.4.0",
"nodemailer": "^6.4.15",
"nodemon": "^2.0.6",
"pm2": "^4.5.0"
Expand Down
2 changes: 2 additions & 0 deletions src/api/index.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
import { Router } from 'express';
import comments from './comments';
import reactions from './reactions';

const router = new Router();

router.use('/comments', comments);
router.use('/reactions', reactions);

export default router;
40 changes: 40 additions & 0 deletions src/api/reactions/controller.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
import Reaction from './model';
import { getPageData } from './helper';
import { asyncRoute } from '../../services/express';

export const add = asyncRoute(async (req, res) => {
const fingerprint = req.headers.fingerprint;
const pageId = req.body.pageId || req.query.pageId;
const reaction = req.body.reaction.slice(0, 20); // Just in case, limit characters by 20

if (!fingerprint) {
return res.status(500).send('Fingerprint required for reacting.');
}

const searchCondition = { pageId, fingerprint };
const recordInDB = await Reaction.findOne(searchCondition);

if (!recordInDB) {
await Reaction.create({ ...searchCondition, reaction });
} else {
if (recordInDB.reaction === reaction) {
await Reaction.deleteOne(recordInDB);
} else {
recordInDB.reaction = reaction;
await recordInDB.save();
}
}

const reactions = await getPageData(searchCondition);

return res.status(200).json(reactions);
});

export const list = asyncRoute(async (req, res) => {
const fingerprint = req.headers.fingerprint;
const pageId = req.body.pageId || req.query.pageId;

const reactions = await getPageData({ pageId, fingerprint });

return res.status(200).json(reactions);
});
24 changes: 24 additions & 0 deletions src/api/reactions/helper.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
import Reaction from './model';

export const getPageData = async ({ fingerprint, pageId }) => {
const userReactionPromise = Reaction.findOne({
fingerprint,
pageId
}).select('reaction -_id');

const aggregationPromise = Reaction.aggregate()
.match({
pageId
})
.group({
_id: '$reaction',
count: { $count: {} }
});

const [aggregation, userReaction] = await Promise.all([
aggregationPromise,
userReactionPromise
]);

return { aggregation, userReaction };
};
9 changes: 9 additions & 0 deletions src/api/reactions/index.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
import { Router } from 'express';
import { list, add } from './controller';

const router = new Router();

router.post('/', add);
router.get('/', list);

export default router;
30 changes: 30 additions & 0 deletions src/api/reactions/model.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import mongoose, { Schema } from 'mongoose';

const schema = new Schema(
{
owner: {
ip: {
type: String,
required: false
}
},
fingerprint: {
type: String,
required: true
},
pageId: {
type: String,
required: true
},
reaction: {
type: String,
}
},
{
timestamps: true
}
);

const model = mongoose.model('Reaction', schema);

export default model;
7 changes: 7 additions & 0 deletions src/services/mailer/index.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
import nodemailer from 'nodemailer';
import moment from 'moment';

if (!process.env.ADMIN_EMAIL_ADDR) {
console.warn('WARNIGN: ADMIN_EMAIL_ADDR Admin email is not present, you will not be notified about new emails.');
}

const transporter = nodemailer.createTransport({
port: 465,
secure: true,
Expand All @@ -12,6 +16,9 @@ const transporter = nodemailer.createTransport({
});

export async function newCommentNotification(comment) {
if (!process.env.ADMIN_EMAIL_ADDR) {
return;
}
const date = moment(comment.createdAt).format('DD.MMM.YYYY - HH:mm');
await transporter.sendMail({
from: `"FooCommmets" <${process.env.BOT_EMAIL_ADDR}>`,
Expand Down
4 changes: 0 additions & 4 deletions src/services/mongoose/index.js
Original file line number Diff line number Diff line change
@@ -1,10 +1,6 @@
import mongoose from 'mongoose';

mongoose.Promise = Promise;
mongoose.set('useNewUrlParser', true);
mongoose.set('useFindAndModify', false);
mongoose.set('useUnifiedTopology', true);
mongoose.set('useCreateIndex', true);

mongoose.connection.on('error', err => {
console.error('MongoDB connection error: ' + err);
Expand Down

0 comments on commit 8c91526

Please sign in to comment.