Commit 70363aeb authored by Ekanayake P.M.D.P IT18013610's avatar Ekanayake P.M.D.P IT18013610

Merge branch 'it18013610' into 'master'

It18013610

See merge request !9
parents 7963cda7 17231558
const { spawn } = require('child_process');
const path = require('path');
const AutomatedAnswer = require('../models/automatedAnswer');
const Question = require('../models/question');
/**
* @Method - POST
* @param {*} question_id - ID of the question to create automated answer for
* @returns Whether the automated answer request created or not
*/
exports.requestAutomatedAnswer = async (req, res, next) => {
const { question_id } = req.body;
try {
const question = await Question.findById(question_id);
if (!question) {
return res
.status(404)
.json({ message: 'No question found for this id, Please try again with another question' });
}
let autoAnswer;
autoAnswer = await AutomatedAnswer.findOne({ question: question_id });
if (autoAnswer) {
return res
.status(303)
.json({ message: 'Automated answer is already generated', automatedanswer: autoAnswer });
}
res.status(201).json({ message: 'Automated answer requested! Please wait for few seconds' });
autoAnswer = await AutomatedAnswer.create({ question: question._id, loading: true });
spawn('python', [
path.join(__dirname, '..', 'python', 'auto-answer', 'scrapper.py'),
question.title,
question.tags,
autoAnswer._id
]);
} catch (err) {
next(err);
}
};
/**
*
* @Method - GET
* @qid {*} - question id
* @returns the automated answer for the question(qid) if there is one
*/
exports.getAutomatedAnswer = async (req, res, next) => {
const { qid } = req.params;
console.log('answer is here' + qid);
try {
const answer = await AutomatedAnswer.findOne({ question: qid });
if (!answer) {
return res.status(404).json({ message: 'No automated answer found for this question' });
}
return res.status(200).json({
message: 'Automated answer found',
automatedanswer: answer
});
} catch (err) {
next(err);
}
};
const Question = require('../models/question'); const Question = require('../models/question');
const User = require('../models/user');
const AutomatedAnswer = require('../models/automatedAnswer'); const AutomatedAnswer = require('../models/automatedAnswer');
const User = require('../models/user');
const { body, validationResult } = require('express-validator'); const { body, validationResult } = require('express-validator');
const { spawn } = require('child_process'); const { spawn } = require('child_process');
const path = require('path'); const path = require('path');
...@@ -35,12 +35,18 @@ exports.createQuestion = async (req, res, next) => { ...@@ -35,12 +35,18 @@ exports.createQuestion = async (req, res, next) => {
}); });
res.status(201).json(question); res.status(201).json(question);
const autoAnswer = await AutomatedAnswer.create({ question: question._id }); const autoAnswer = await AutomatedAnswer.create({ question: question._id });
spawn('python', [ const pythonScript = spawn('python', [
path.join(__dirname, '..', 'python', 'auto-answer', 'scrapper.py'), path.join(__dirname, '..', 'python', 'auto-answer', 'scrapper.py'),
title, title,
tags, tags,
autoAnswer._id autoAnswer._id
]); ]);
pythonScript.stdout.on('data', (data) => {
console.log('DATA FROM PYTHON IS HERE' + data);
});
pythonScript.stdout.on('end', function () {
console.log('PYTHON SCRIPT HAS BEEN ENDED');
});
} catch (error) { } catch (error) {
next(error); next(error);
} }
...@@ -96,6 +102,7 @@ exports.removeQuestion = async (req, res, next) => { ...@@ -96,6 +102,7 @@ exports.removeQuestion = async (req, res, next) => {
try { try {
await req.question.remove(); await req.question.remove();
res.json({ message: 'Your question successfully deleted.' }); res.json({ message: 'Your question successfully deleted.' });
await AutomatedAnswer.findOneAndRemove({ question: req.question._id });
} catch (error) { } catch (error) {
next(error); next(error);
} }
...@@ -113,22 +120,6 @@ exports.loadComment = async (req, res, next, id) => { ...@@ -113,22 +120,6 @@ exports.loadComment = async (req, res, next, id) => {
next(); next();
}; };
exports.getAutomatedAnswer = async (req, res, next) => {
console.log('HERE');
try {
const { q } = req.params;
const answer = await AutomatedAnswer.findOne({ question: q });
if (answer) {
res.json(answer);
} else {
res.status(404).json({ msg: 'No automated answer found' });
}
} catch (error) {
next(error);
}
};
exports.questionValidate = [ exports.questionValidate = [
body('title') body('title')
.exists() .exists()
......
...@@ -9,7 +9,11 @@ class DevTo: ...@@ -9,7 +9,11 @@ class DevTo:
self.title = title self.title = title
self.tags = tags self.tags = tags
def getApiKey(self): def get_api_key(self):
"""
get random api key from api keys of rss2json.com
:return: string
"""
api_keys = [ api_keys = [
"2rk1eg4sexdnp5umrwtwbtwd2insqvgzvejooqrn", "2rk1eg4sexdnp5umrwtwbtwd2insqvgzvejooqrn",
"yit6ytfcs3ziawdgasfd3bgkbf4tef1m2nzdxvnz", "yit6ytfcs3ziawdgasfd3bgkbf4tef1m2nzdxvnz",
...@@ -23,7 +27,10 @@ class DevTo: ...@@ -23,7 +27,10 @@ class DevTo:
gresults = gsearch.search(*search_args) gresults = gsearch.search(*search_args)
return gresults["links"] return gresults["links"]
def getValidUrls(self, links): def get_valid_urls(self, links):
"""
filter out invalid urls
"""
validUrls = [] validUrls = []
for i in links: for i in links:
if "dev.to" in i: if "dev.to" in i:
...@@ -32,7 +39,10 @@ class DevTo: ...@@ -32,7 +39,10 @@ class DevTo:
validUrls.append(ur) validUrls.append(ur)
return validUrls return validUrls
def getValidSets(self, validUrls): def get_valid_sets(self, validUrls):
"""
extract valid usernames and tags from valid dev.to urls
"""
validSets = [] validSets = []
for url in validUrls: for url in validUrls:
try: try:
...@@ -48,11 +58,14 @@ class DevTo: ...@@ -48,11 +58,14 @@ class DevTo:
continue continue
return validSets return validSets
def getBlogs(self, username, tag): def get_blogs(self, username, tag):
"""
get the contents of the dev.to article
"""
blog = {} blog = {}
try: try:
response = requests.get( response = requests.get(
f"https://api.rss2json.com/v1/api.json?rss_url=https%3A%2F%2Fdev.to%2Ffeed%2F{username}&api_key={self.getApiKey()}" f"https://api.rss2json.com/v1/api.json?rss_url=https%3A%2F%2Fdev.to%2Ffeed%2F{username}&api_key={self.get_api_key()}"
) )
if response.status_code == 200: if response.status_code == 200:
res = response.json() res = response.json()
...@@ -63,13 +76,20 @@ class DevTo: ...@@ -63,13 +76,20 @@ class DevTo:
print(e) print(e)
return blog return blog
def getDevArticles(self): def get_dev_articles(self):
"""
Search google for dev.to articles
return a list of urls
filter out invalid urls
get content of the valid urls
return the content of valid dev.to articles
"""
links = self.google(f"site:dev.to {self.title} after:2020-01-01") links = self.google(f"site:dev.to {self.title} after:2020-01-01")
validUrls = self.getValidUrls(links) validUrls = self.get_valid_urls(links)
validSets = self.getValidSets(validUrls) validSets = self.get_valid_sets(validUrls)
blogs = [] blogs = []
for validset in validSets: for validset in validSets:
blog = self.getBlogs(validset["username"], validset["tag"]) blog = self.get_blogs(validset["username"], validset["tag"])
if bool(blog): if bool(blog):
blogs.append(blog) blogs.append(blog)
return {"blogs": blogs, "resources": validUrls} return {"blogs": blogs, "resources": validUrls}
import requests
from search_engine_parser import GoogleSearch
import re
class Github:
"""
A class to manage the Github API.
"""
def __init__(self):
"""
Initialize the Github API.
"""
def get_github_resources(self, query):
"""
this function will search github for a query and return a list of links if available,
if not available it will search google for the query and return a list of links.
"""
github = {}
github_repos = self.search_github_repos(query)
github_links = self.search_github_repos_in_google(query)
valid_github_links = self.get_valid_urls(github_links)
github["links"] = valid_github_links
github["repos"] = self.get_first_ten_repos(github_repos["items"])
return github
def get_first_ten_repos(self, repos):
"""
Get the first ten repos if more than 10 repos are found.
otherwise return all repos.
:param repos: The repos.
"""
if len(repos) > 10:
return repos[:10]
else:
return repos
def get_user_repos(self, user):
"""
Get the repos of a user.
:param user: The Github user.
:return: The repos of the user.
"""
url = "https://api.github.com/users/{}/repos".format(user)
response = requests.get(url)
response.raise_for_status()
return response.json()
def search_github_repos(self, query):
"""
Search for repos on Github.
:param query: The search query.
:return: The repos found.
"""
url = "https://api.github.com/search/repositories?q={}".format(query)
response = requests.get(url)
response.raise_for_status()
return response.json()
def search_github_repos_in_google(self, query):
"""
Search for repos on Github using google search enging.
:param query: The search query.
:return: The repos found.
"""
google_query = "site:github.com {}".format(query)
search_args = (google_query, 1)
gsearch = GoogleSearch()
gresults = gsearch.search(*search_args)
return gresults["links"]
def get_valid_urls(self, links):
"""
filter out invalid urls
"""
validUrls = []
for i in links:
if "github.com" in i:
uriTrimmed = re.match(r"^.*?\&sa=", i[29:]).group(0)
ur = uriTrimmed.replace("&sa=", "")
validUrls.append(ur)
return validUrls
\ No newline at end of file
...@@ -2,11 +2,12 @@ from youtube import Youtube ...@@ -2,11 +2,12 @@ from youtube import Youtube
from Medium import Medium from Medium import Medium
from Dev import DevTo from Dev import DevTo
from stof import STOF from stof import STOF
from Github import Github
import sys import sys
from database import get_database from database import get_database
def saveAnswer(ans_id, stackoverflow, videos, medium_r, dev_r): def saveAnswer(ans_id, stackoverflow, videos, medium_r, dev_r, github_r):
db = get_database() db = get_database()
try: try:
from bson.objectid import ObjectId from bson.objectid import ObjectId
...@@ -16,12 +17,15 @@ def saveAnswer(ans_id, stackoverflow, videos, medium_r, dev_r): ...@@ -16,12 +17,15 @@ def saveAnswer(ans_id, stackoverflow, videos, medium_r, dev_r):
{"_id": ObjectId(ans_id)}, {"_id": ObjectId(ans_id)},
{ {
"$set": { "$set": {
"loading":False,
"youtube": videos, "youtube": videos,
"stackoverflow": stackoverflow, "stackoverflow": stackoverflow,
"medium_articles": medium_r["blogs"], "medium_articles": medium_r.get("blogs", []),
"dev_articles": dev_r["blogs"], "dev_articles": dev_r.get("blogs", []),
"medium_resources": medium_r["resources"], "medium_resources": medium_r.get("resources", []),
"dev_resources": dev_r["resources"], "dev_resources": dev_r.get("resources", []),
"github_repos": github_r.get("repos", []),
"github_links": github_r.get("links", []),
} }
}, },
) )
...@@ -33,29 +37,34 @@ def saveAnswer(ans_id, stackoverflow, videos, medium_r, dev_r): ...@@ -33,29 +37,34 @@ def saveAnswer(ans_id, stackoverflow, videos, medium_r, dev_r):
"dev_articles": dev_r["blogs"], "dev_articles": dev_r["blogs"],
"medium_resources": medium_r["resources"], "medium_resources": medium_r["resources"],
"dev_resources": dev_r["resources"], "dev_resources": dev_r["resources"],
"github_repos": github_r["repos"],
"github_links": github_r["links"],
} }
) )
except NameError as err: except NameError as err:
print("ERRORRR")
print(err) print(err)
if __name__ == "__main__": if __name__ == "__main__":
# title = input("Enter question title: ") # title = input("Enter question title: ")
title = sys.argv[1] # "python django or flask for web development" title = sys.argv[1]
tags = sys.argv[2] # ["react"] # "what are the benefits of using java for mobile app development over flutter"
AUTO_ANS_ID = sys.argv[3] # "60dc9a5f84692f001569d7ab" tags = sys.argv[2] # ["flutter","java"]
AUTO_ANS_ID = sys.argv[3] # "611feaff2c4db730e56d78e8"
stack = STOF(title) stack = STOF(title)
ans = stack.searchQuestion()
print(ans)
medium = Medium(title, tags) medium = Medium(title, tags)
medium_articels = medium.getMediumArticles()
devto = DevTo(title, tags) devto = DevTo(title, tags)
dev_articles = devto.getDevArticles()
youtube = Youtube(title, tags) youtube = Youtube(title, tags)
github = Github()
ans = stack.searchQuestion()
medium_articels = medium.getMediumArticles()
dev_articles = devto.get_dev_articles()
videos = youtube.find_videos() videos = youtube.find_videos()
saveAnswer(AUTO_ANS_ID, ans, videos, medium_articels, dev_articles) github_resources = github.get_github_resources(title)
saveAnswer(
AUTO_ANS_ID, ans, videos, medium_articels, dev_articles, github_resources
)
print("WORKED") print("WORKED")
sys.stdout.flush() sys.stdout.flush()
...@@ -14,8 +14,7 @@ const { ...@@ -14,8 +14,7 @@ const {
listQuestions, listQuestions,
listByTags, listByTags,
listByUser, listByUser,
removeQuestion, removeQuestion
getAutomatedAnswer
} = require('./controllers/questions'); } = require('./controllers/questions');
const { const {
loadAnswers, loadAnswers,
...@@ -31,6 +30,7 @@ const requireAuth = require('./middlewares/requireAuth'); ...@@ -31,6 +30,7 @@ const requireAuth = require('./middlewares/requireAuth');
const questionAuth = require('./middlewares/questionAuth'); const questionAuth = require('./middlewares/questionAuth');
const commentAuth = require('./middlewares/commentAuth'); const commentAuth = require('./middlewares/commentAuth');
const answerAuth = require('./middlewares/answerAuth'); const answerAuth = require('./middlewares/answerAuth');
const { requestAutomatedAnswer, getAutomatedAnswer } = require('./controllers/automated-answer');
const router = require('express').Router(); const router = require('express').Router();
...@@ -51,7 +51,6 @@ router.get('/question', listQuestions); ...@@ -51,7 +51,6 @@ router.get('/question', listQuestions);
router.get('/questions/:tags', listByTags); router.get('/questions/:tags', listByTags);
router.get('/question/user/:username', listByUser); router.get('/question/user/:username', listByUser);
router.delete('/question/:question', [requireAuth, questionAuth], removeQuestion); router.delete('/question/:question', [requireAuth, questionAuth], removeQuestion);
router.get('/automatedanswer/:q', getAutomatedAnswer);
//tags //tags
router.get('/tags/populertags', listPopulerTags); router.get('/tags/populertags', listPopulerTags);
...@@ -74,6 +73,10 @@ router.post('/comment/:question/:answer?', [requireAuth, validate], createCommen ...@@ -74,6 +73,10 @@ router.post('/comment/:question/:answer?', [requireAuth, validate], createCommen
router.delete('/comment/:question/:comment', [requireAuth, commentAuth], removeComment); router.delete('/comment/:question/:comment', [requireAuth, commentAuth], removeComment);
router.delete('/comment/:question/:answer/:comment', [requireAuth, commentAuth], removeComment); router.delete('/comment/:question/:answer/:comment', [requireAuth, commentAuth], removeComment);
//automate-answer
router.post('/automatedanswer', requireAuth, requestAutomatedAnswer);
router.get('/automatedanswer/:qid', getAutomatedAnswer);
module.exports = (app) => { module.exports = (app) => {
app.use('/api', router); app.use('/api', router);
......
import React, { useState } from 'react'
import Pagination from '../pagination/Pagination'
const AutomatedAnswerSwiper = ({ children }) => {
const [currentIndex, setCurrentIndex] = useState(0)
const onBtnClick = (index) => {
console.log('here' + index)
if (index < children.length) {
setCurrentIndex(index)
}
}
return (
<div className="automated">
<Pagination
currentIndex={currentIndex}
length={children.length}
onBtnClick={onBtnClick}
onClickFirst={() => setCurrentIndex(0)}
onClickLast={() => setCurrentIndex(children.length - 1)}
/>
{children[currentIndex]}
</div>
)
}
export default AutomatedAnswerSwiper
import React from 'react'
import styles from './Pagination.module.css'
const Pagination = ({
currentIndex,
length,
onBtnClick,
onClickFirst,
onClickLast
}) => {
return (
<div className={styles.pagination_wrapper}>
<span onClick={onClickFirst} className={styles.cursor}>
first
</span>
<div className={styles.numbering}>
{new Array(length).fill(0).map((item, index) => {
return (
<span
className={
index == currentIndex
? styles.active_number
: styles.muted_number
}
key={index}
onClick={() => onBtnClick(index)}
>
{index + 1}
</span>
)
})}
{/* <span className={styles.active_number}>{currentIndex + 1}</span>/
<span className={styles.muted_number}>{length}</span> */}
</div>
<span onClick={onClickLast} className={styles.cursor}>
last
</span>
</div>
)
}
export default Pagination
.pagination_wrapper {
display: flex;
flex-direction: row;
justify-content: space-between;
}
.numbering {
color: #999;
* {
margin: 0 2px;
cursor: pointer;
}
}
.active_number {
color: #fff;
padding: 2px 10px;
background-color: #13ff625c;
border: 1px solid #78ff78;
}
.muted_number {
color: #fff;
padding: 2px 10px;
background-color: #5d5d5d5c;
border: 1px solid #9c9c9c;
}
.cursor {
cursor: pointer;
}
import React from 'react' import React from 'react'
import AutomatedAnswerSwiper from '../automated-answer-swiper/AutomatedAnswerSwiper'
import YoutubeVideo from './youtube-video/YoutubeVideo' import YoutubeVideo from './youtube-video/YoutubeVideo'
import styles from './YoutubeVideoWrapper.module.css' import styles from './YoutubeVideoWrapper.module.css'
const YoutubeVideoWrapper = ({ videos }) => { const YoutubeVideoWrapper = ({ videos }) => {
...@@ -9,9 +10,11 @@ const YoutubeVideoWrapper = ({ videos }) => { ...@@ -9,9 +10,11 @@ const YoutubeVideoWrapper = ({ videos }) => {
youtube youtube
</h1> </h1>
<div className={styles.wrapper}> <div className={styles.wrapper}>
{videos.map((video, index) => { <AutomatedAnswerSwiper>
return <YoutubeVideo video={video} key={index} /> {videos.map((video, index) => {
})} return <YoutubeVideo video={video} key={index} />
})}
</AutomatedAnswerSwiper>
</div> </div>
</> </>
) )
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment