Commit 7963cda7 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 !8
parents d49badaa f2718707
...@@ -29,10 +29,38 @@ const AutomatedAnswerSchema = mongoose.Schema({ ...@@ -29,10 +29,38 @@ const AutomatedAnswerSchema = mongoose.Schema({
type: String type: String
} }
], ],
blogs: [ medium_articles: [
{ {
type: Schema.Types.ObjectId, title: String,
ref: 'BlogArticle' pubDate: String,
link: String,
guid: String,
author: String,
thumbnail: String,
description: String,
content: String
}
],
dev_articles: [
{
title: String,
pubDate: String,
link: String,
guid: String,
author: String,
thumbnail: String,
description: String,
content: String
}
],
medium_resources: [
{
type: String
}
],
dev_resources: [
{
type: String
} }
] ]
}); });
......
const mongoose = require('mongoose');
const BlogArticleSchema = mongoose.Schema({
automatedAnswer: {
type: Schema.Types.ObjectId,
ref: 'AutomatedAnswer',
required: true
},
blogName: {
type: String,
required: true
},
link: {
type: String,
required: true
},
content: {
type: String
}
});
module.exports = mongoose.model('BlogArticle', BlogArticleSchema);
from search_engine_parser import GoogleSearch
import re
import requests
import random
class DevTo:
def __init__(self, title, tags):
self.title = title
self.tags = tags
def getApiKey(self):
api_keys = [
"2rk1eg4sexdnp5umrwtwbtwd2insqvgzvejooqrn",
"yit6ytfcs3ziawdgasfd3bgkbf4tef1m2nzdxvnz",
"mpawymyrc6derrwmgodowfsaabtuoes4iiwintd7",
]
return random.choice(api_keys)
def google(self, query):
search_args = (query, 1)
gsearch = GoogleSearch()
gresults = gsearch.search(*search_args)
return gresults["links"]
def getValidUrls(self, links):
validUrls = []
for i in links:
if "dev.to" in i:
uriTrimmed = re.match(r"^.*?\&sa=", i[29:]).group(0)
ur = uriTrimmed.replace("&sa=", "")
validUrls.append(ur)
return validUrls
def getValidSets(self, validUrls):
validSets = []
for url in validUrls:
try:
vset = {}
print(url)
username = re.search(r"https://dev.to/([^/?]+)", url).group(1)
tag = re.search(r"https://dev.to/([^/?]+)/([^/?]+)", url).group(2)
vset["username"] = username
vset["tag"] = tag
validSets.append(vset)
except Exception as e:
print(e)
continue
return validSets
def getBlogs(self, username, tag):
blog = {}
try:
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()}"
)
if response.status_code == 200:
res = response.json()
for item in res["items"]:
if tag in item["link"]:
blog = item
except Exception as e:
print(e)
return blog
def getDevArticles(self):
links = self.google(f"site:dev.to {self.title} after:2020-01-01")
validUrls = self.getValidUrls(links)
validSets = self.getValidSets(validUrls)
blogs = []
for validset in validSets:
blog = self.getBlogs(validset["username"], validset["tag"])
if bool(blog):
blogs.append(blog)
return {"blogs": blogs, "resources": validUrls}
import requests import json
from requests_html import HTMLSession from search_engine_parser import GoogleSearch
from bs4 import BeautifulSoup
import re import re
from lxml import etree import requests
import random
class Medium: class Medium:
def __init__(self, qtitle, keywords=[], description=""): def __init__(self, title, tags):
self.qtitle = qtitle self.title = title
self.keywords = keywords self.tags = tags
self.description = description
self.urls = [] def getApiKey(self):
self.session = HTMLSession() """
Returns an API key for retrieve json data
def searchArticles(self): """
""" api_keys = [
Search details using google dorks, "2rk1eg4sexdnp5umrwtwbtwd2insqvgzvejooqrn",
With google dorks we can filter out other search results from other web sites. "yit6ytfcs3ziawdgasfd3bgkbf4tef1m2nzdxvnz",
""" "mpawymyrc6derrwmgodowfsaabtuoes4iiwintd7",
html_page = requests.get( ]
f"https://google.com/search?q=site%3Amedium.com+{self.qtitle}" return random.choice(api_keys)
)
def google(self, query):
soup = BeautifulSoup(html_page.content, "html.parser") """
Use a query to search using google search enging
for link in soup.findAll("a"): """
if "https://medium.com" in link["href"]: search_args = (query, 1)
self.urls.append(self.extractMediumURLS(link["href"])) gsearch = GoogleSearch()
self.viewArticle(self.urls[0]) gresults = gsearch.search(*search_args)
return gresults["links"]
def extractMediumURLS(self, uriString):
""" def getValidUrls(self, links):
Remove unwanted characters from the url string and filter out the targeted url """
""" Validate and filter out the urls.
uriTrimmed = uriString[7:] Returns the urls that contain medium.com in it as a list
uriTrimmed = re.match(r"^.*?\&sa=", uriTrimmed).group(0) """
return uriTrimmed.replace("&sa=", "") validUrls = []
for i in links:
def viewArticle(self, url): if "medium.com" in i:
html_page = self.session.get(url) uriTrimmed = re.match(r"^.*?\&sa=", i[29:]).group(0)
html_page.html.render(timeout=20) ur = uriTrimmed.replace("&sa=", "")
validUrls.append(ur)
# soup = BeautifulSoup(html_page.content, "html.parser") return validUrls
# dom = etree.HTML(str(soup))
with open("medium.html", "wb") as med: def getValidSets(self, validUrls):
med.write(html_page.content) """
med.close() Extract usernames and article id's from article url
with open("medium.html", encoding="utf8") as sf: pass a list of urls => returns objects list that contain usernam and article id
soup = BeautifulSoup(sf, "html.parser") """
dom = etree.HTML(str(soup)) validSets = []
# art = dom.xpath('//*[@class="a b c"]')[0] for url in validUrls:
# print(etree.tostring(art)) try:
title = dom.xpath('//*[@class="ap aq ar as at ff av w"]/div/h1')[0].text vset = {}
article = dom.xpath('//*[@class="ap aq ar as at ff av w"]')[0] print(url)
with open(f"article-{title.replace(' ','')}.html", "wb") as artFile: username = re.search(r"https://medium.com/([^/?]+)", url).group(1)
artFile.write(etree.tostring(article)) tag = re.search(r"https://medium.com/([^/?]+)/([^/?]+)", url).group(2)
artFile.close() vset["username"] = username
vset["tag"] = tag
validSets.append(vset)
except Exception as e:
print(e)
continue
return validSets
def getBlogs(self, username, tag):
"""
Get the content of the article
"""
blog = {}
try:
response = requests.get(
f"https://api.rss2json.com/v1/api.json?rss_url=https%3A%2F%2Fmedium.com%2Ffeed%2F{username}&api_key={self.getApiKey()}"
)
if response.status_code == 200:
res = response.json()
for item in res["items"]:
if tag in item["link"]:
blog = item
except Exception as e:
print(e)
return blog
def getMediumArticles(self):
"""
return a list of articles and/or resources
"""
links = self.google(f"site:medium.com {self.title} after:2020-01-01")
validUrls = self.getValidUrls(links)
validSets = self.getValidSets(validUrls)
blogs = []
for validset in validSets:
blog = self.getBlogs(validset["username"], validset["tag"])
if bool(blog):
blogs.append(blog)
return {"blogs": blogs, "resources": validUrls}
bson==0.5.10
beautifulsoup4==4.9.3 beautifulsoup4==4.9.3
dnspython==2.1.0 dnspython==2.1.0
lxml==4.6.1 lxml==4.6.1
...@@ -6,4 +7,5 @@ regex==2020.7.14 ...@@ -6,4 +7,5 @@ regex==2020.7.14
requests==2.24.0 requests==2.24.0
requests-html==0.10.0 requests-html==0.10.0
scipy==1.5.4 scipy==1.5.4
search-engine-parser==0.6.2
youtube-search-python==1.4.6
from youtube import Youtube from youtube import Youtube
from Medium import Medium from Medium import Medium
from Dev import DevTo
from stof import STOF from stof import STOF
import sys import sys
from database import get_database from database import get_database
def saveAnswer(ans_id, stackoverflow, videos): def saveAnswer(ans_id, stackoverflow, videos, medium_r, dev_r):
db = get_database() db = get_database()
try: try:
from bson.objectid import ObjectId from bson.objectid import ObjectId
...@@ -13,7 +14,26 @@ def saveAnswer(ans_id, stackoverflow, videos): ...@@ -13,7 +14,26 @@ def saveAnswer(ans_id, stackoverflow, videos):
automatedanswers = db["automatedanswers"] automatedanswers = db["automatedanswers"]
automatedanswers.update_one( automatedanswers.update_one(
{"_id": ObjectId(ans_id)}, {"_id": ObjectId(ans_id)},
{"$set": {"youtube": videos, "stackoverflow": stackoverflow}}, {
"$set": {
"youtube": videos,
"stackoverflow": stackoverflow,
"medium_articles": medium_r["blogs"],
"dev_articles": dev_r["blogs"],
"medium_resources": medium_r["resources"],
"dev_resources": dev_r["resources"],
}
},
)
print(
{
"youtube": videos,
"stackoverflow": stackoverflow,
"medium_articles": medium_r["blogs"],
"dev_articles": dev_r["blogs"],
"medium_resources": medium_r["resources"],
"dev_resources": dev_r["resources"],
}
) )
except NameError as err: except NameError as err:
print(err) print(err)
...@@ -23,19 +43,19 @@ if __name__ == "__main__": ...@@ -23,19 +43,19 @@ 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] # "python django or flask for web development"
tags = sys.argv[2] # ["react"] tags = sys.argv[2] # ["react"]
AUTO_ANS_ID = sys.argv[3] # "60d746076689344694ad9e30" # AUTO_ANS_ID = sys.argv[3] # "60dc9a5f84692f001569d7ab"
stack = STOF(title) stack = STOF(title)
ans = stack.searchQuestion() ans = stack.searchQuestion()
print(ans) print(ans)
# medium = Medium(title) medium = Medium(title, tags)
# medium.searchArticles() medium_articels = medium.getMediumArticles()
# f = open("data.txt", "a")
# f.write(f"updated {title} {tags} {AUTO_ANS_ID}\n") devto = DevTo(title, tags)
# f.close() dev_articles = devto.getDevArticles()
youtube = Youtube(title, tags) youtube = Youtube(title, tags)
videos = youtube.find_videos() videos = youtube.find_videos()
saveAnswer(AUTO_ANS_ID, ans, videos) saveAnswer(AUTO_ANS_ID, ans, videos, medium_articels, dev_articles)
print("WORKED") print("WORKED")
sys.stdout.flush() sys.stdout.flush()
...@@ -7,4 +7,5 @@ regex==2020.7.14 ...@@ -7,4 +7,5 @@ regex==2020.7.14
requests==2.24.0 requests==2.24.0
requests-html==0.10.0 requests-html==0.10.0
scipy==1.5.4 scipy==1.5.4
search-engine-parser==0.6.2
youtube-search-python==1.4.6 youtube-search-python==1.4.6
import React from 'react' import React from 'react'
import StackOverflowAnswer from '../stof-answer' import StackOverflowAnswer from '../stof-answer'
import YoutubeVideoWrapper from '../youtube-videos/YoutubeVideoWrapper'
const AutomatedAnswer = ({ automatedAnswer }) => { const AutomatedAnswer = ({ automatedAnswer }) => {
console.log(automatedAnswer) console.log(automatedAnswer)
...@@ -10,6 +11,13 @@ const AutomatedAnswer = ({ automatedAnswer }) => { ...@@ -10,6 +11,13 @@ const AutomatedAnswer = ({ automatedAnswer }) => {
) : ( ) : (
<h1>No Stack overflow</h1> <h1>No Stack overflow</h1>
)} )}
{automatedAnswer.youtube != null &&
automatedAnswer.youtube.length >= 1 ? (
<YoutubeVideoWrapper videos={automatedAnswer.youtube} />
) : (
<h1>No youtubes found for this question</h1>
)}
</> </>
) )
} }
......
...@@ -7,7 +7,9 @@ const StackOverflowAnswer = ({ stof }) => { ...@@ -7,7 +7,9 @@ const StackOverflowAnswer = ({ stof }) => {
} }
return ( return (
<> <>
<h1 className={styles.h}>Answer from Stackoverflow - {stof.status}</h1> <h1 className={styles.h}>
I found {stof.status} answer on Stackoverflow
</h1>
<div className={styles.wrapper}> <div className={styles.wrapper}>
<div dangerouslySetInnerHTML={createMarkup()}></div> <div dangerouslySetInnerHTML={createMarkup()}></div>
</div> </div>
......
...@@ -5,8 +5,10 @@ ...@@ -5,8 +5,10 @@
padding: 0.8em; padding: 0.8em;
border-radius: 10px; border-radius: 10px;
font-family: 'Open Sans', sans-serif; font-family: 'Open Sans', sans-serif;
margin-bottom: 3em;
color: white;
} }
.h { .h {
font-size: 1.3em !important; font-size: 2em !important;
} }
import React from 'react'
import YoutubeVideo from './youtube-video/YoutubeVideo'
import styles from './YoutubeVideoWrapper.module.css'
const YoutubeVideoWrapper = ({ videos }) => {
return (
<>
<h1 className={styles.h1}>
Here are {videos.length} video{videos.length > 1 && 's'} I found on
youtube
</h1>
<div className={styles.wrapper}>
{videos.map((video, index) => {
return <YoutubeVideo video={video} key={index} />
})}
</div>
</>
)
}
export default YoutubeVideoWrapper
.wrapper {
margin-top: 0.5em;
background-color: #2d2d2d;
padding: 0.8em;
border-radius: 2px;
margin-bottom: 3em;
}
.h1 {
font-size: 2em !important;
}
import React from 'react'
import styles from './YoutubeVideo.module.css'
const YoutubeVideo = ({ video }) => {
console.log(video.substring(32, video.length - 1))
return (
<div className={styles.video_responsive}>
<iframe
width="853"
height="480"
src={`https://youtube.com/embed/${video.substring(32, video.length)}`}
frameBorder="0"
allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture"
allowFullScreen
title="Embedded youtube"
/>
</div>
)
}
export default YoutubeVideo
.video_responsive {
overflow: hidden;
padding-bottom: 56.25%;
position: relative;
height: 0;
margin: 1em 0;
iframe {
left: 0;
top: 0;
height: 100%;
width: 100%;
position: absolute;
}
}
...@@ -4,7 +4,7 @@ ...@@ -4,7 +4,7 @@
line-height: 1.5em; line-height: 1.5em;
word-break: break-word; word-break: break-word;
font-size: 15px; font-size: 15px;
color: white;
a { a {
text-decoration: underline; text-decoration: underline;
color: var(--blue-300); color: var(--blue-300);
...@@ -43,6 +43,13 @@ ...@@ -43,6 +43,13 @@
margin-top: 0.6em; margin-top: 0.6em;
} }
} }
h2 {
color: white !important;
font-weight: bold !important;
font-size: 1.4em !important;
margin: 1.6em 0 0.7em 0;
}
} }
.s-prose *:not(.s-code-block) > code { .s-prose *:not(.s-code-block) > code {
...@@ -65,3 +72,40 @@ sup { ...@@ -65,3 +72,40 @@ sup {
sub { sub {
vertical-align: sub; vertical-align: sub;
} }
.s-table-container {
/* margin-bottom: 1.1em; */
overflow-x: auto;
}
.s-table {
display: table;
width: 100%;
max-width: 100%;
border-collapse: collapse;
border-spacing: 0;
font-size: 13px;
}
.s-table thead th {
vertical-align: bottom;
white-space: nowrap;
background-color: var(--black-600);
line-height: 1.15384615;
}
.s-table th {
font-weight: bold;
color: var(--fc-dark);
}
.s-table th,
.s-table td {
padding: 8px;
border-top: 1px solid var(--black-100);
border-left: 1px solid var(--black-100);
border-right: 1px solid var(--black-100);
vertical-align: middle;
color: var(--fc-medium);
text-align: left;
}
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