Skip to content

Commit

Permalink
[Lesson] Count number of views per lesson
Browse files Browse the repository at this point in the history
  • Loading branch information
iampava committed May 3, 2021
1 parent 63abc5d commit 38a2b7d
Show file tree
Hide file tree
Showing 5 changed files with 136 additions and 2 deletions.
18 changes: 16 additions & 2 deletions client/components/lessons/Lesson.tsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,9 @@
import React, { PropsWithChildren, useRef, useState } from 'react';
import React, {
PropsWithChildren,
useEffect,
useRef,
useState,
} from 'react';
import Header from '~/components/Header';
import Footer from '~/components/Footer';
import { LessonMenu } from '~/components/lessons';
Expand All @@ -8,6 +13,7 @@ import { withSmoothScroll } from '~/services/Hooks';
import { getLessonById, GITHUB_URL } from '~/services/Constants';
import LessonExercises from './LessonExercises/LessonExercises';
import { Chapter } from '../TableOfContents';
import LessonService from '~/services/api/Lesson.service';

interface Props {
id: string;
Expand All @@ -33,7 +39,7 @@ export default function Lesson({
articleWrapper.current.scrollTo(0, 0);
};

const parseChapters = (chapters: {title: string; id: string}[]) => {
const parseChapters = (chapters: { title: string; id: string }[]) => {
return chapters.map(parseOneChapter);

function parseOneChapter(chapter: Chapter) {
Expand All @@ -47,6 +53,14 @@ export default function Lesson({

const chaptersWithHref = parseChapters(chapters);

useEffect(() => {
LessonService
.increaseViews(id)
.catch((err) => {
console.error('[Lesson.tsx] got while trying to update view count', err);
});
}, []);

return (
<div className={styles.lesson}>
<LessonMenu
Expand Down
17 changes: 17 additions & 0 deletions client/services/api/Lesson.service.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import HttpService from '../Http.service';

class LessonService {
static get(lessonId: string) {
return HttpService
.get(`${process.env.ENDPOINT}/lessons/${lessonId}`)
.then((resp) => resp.json());
}

static increaseViews(lessonId: string) {
return HttpService
.post(`${process.env.ENDPOINT}/lessons/${lessonId}/views`)
.then((resp) => resp.json());
}
}

export default LessonService;
59 changes: 59 additions & 0 deletions server/lesson/lesson.model.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
const mongoose = require('mongoose');
const { ServerError } = require('../ServerUtils');

const LessonsSchema = new mongoose.Schema({
lessonId: { type: String, required: true, unique: true },
views: { type: Number, required: true },
}, {
timestamps: {
updatedAt: 'updatedAt',
},
});

const Lesson = mongoose.models.Lesson || mongoose.model('Lesson', LessonsSchema);

class LessonModel {
static get(lessonId) {
return Lesson.findOne({ lessonId });
}

static async updateViews(lessonId, views) {
let lesson = null;

try {
lesson = await LessonModel.get(lessonId);
} catch (err) {
console.error(`
[LessonModel.updateViews] got while fetching for lessonId=${lessonId}`,
err
);

throw err;
}

if (!lesson) {
lesson = new Lesson({ lessonId });
console.log(`[LessonModel.updateViews] created lesson on demand, with id=${lessonId}`);
}

lesson.views = views;

return new Promise((resolve, reject) => {
lesson.save((err) => {
if (err) {
console.error(`
[LessonModel.updateViews] got while saving lessonId=${lessonId}`,
err
);

reject(err);
return;
}

resolve();
});
});
}
}

module.exports = LessonModel;
42 changes: 42 additions & 0 deletions server/lesson/lesson.router.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
const express = require('express');
const LessonModel = require('./lesson.model');
const { ServerError } = require('../ServerUtils');

const lessonRouter = express.Router();

lessonRouter.get('/:lessonId', async function getLesson(req, res) {
const { lessonId } = req.params;
const lesson = await LessonModel.get(lessonId);

if (!lesson) {
new ServerError(404, `Lesson with id=${lessonId} doesn't exist!`).send(res);
return;
}

res.json(lesson);
});

lessonRouter.post('/:lessonId/views', async function increaseViews(req, res) {
const { lessonId } = req.params;

const lesson = await LessonModel.get(lessonId);

try {
if (!lesson) {
await LessonModel.updateViews(lessonId, 1);
} else {
await LessonModel.updateViews(lessonId, lesson.views + 1);
}

const updatedLesson = await LessonModel.get(lessonId);
res.json(updatedLesson);
} catch (err) {
new ServerError(
err.code || 500,
err.message || 'Oops! A apărut o problemă. Încearcă din nou!'
);
}
});


module.exports = lessonRouter;
2 changes: 2 additions & 0 deletions server/server.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ const demoRouter = require('./demo.router');
const eventRouter = require('./event/event.router');
const githubRouter = require('./github/github.router.js');
const challengeRouter = require('./challenge/challenge.router.js');
const lessonRouter = require('./lesson/lesson.router');

const port = process.env.PORT || 3000;
const app = express();
Expand Down Expand Up @@ -52,6 +53,7 @@ app.use('/api/demo', demoRouter);
app.use('/api/events', eventRouter);
app.use('/api/github', githubRouter);
app.use('/api/challenges', challengeRouter);
app.use('/api/lessons', lessonRouter);

app.get('*', (req, res) => {
nextHandler(req, res, req.url);
Expand Down

0 comments on commit 38a2b7d

Please sign in to comment.