Skip to content
This repository has been archived by the owner on Jun 27, 2019. It is now read-only.

Create an web-app for comments analysis #301

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions 2230/3/Gemfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
source 'https://rubygems.org/'
gem 'capybara'
gem 'sinatra'

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bundler/OrderedGems: Gems should be sorted in an alphabetical order within their section of the Gemfile. Gem sinatra should appear before sinatra-config-file.

gem 'sinatra-config-file'
gem 'shotgun'

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bundler/OrderedGems: Gems should be sorted in an alphabetical order within their section of the Gemfile. Gem shotgun should appear before sinatra-config-file.

gem 'thin'
gem 'ohm'

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bundler/OrderedGems: Gems should be sorted in an alphabetical order within their section of the Gemfile. Gem ohm should appear before thin.

gem 'slim'
gem 'pry'

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Bundler/OrderedGems: Gems should be sorted in an alphabetical order within their section of the Gemfile. Gem pry should appear before slim.

99 changes: 99 additions & 0 deletions 2230/3/Gemfile.lock
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
GEM
remote: https://rubygems.org/
specs:
activesupport (5.2.0)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2)
minitest (~> 5.1)
tzinfo (~> 1.1)
addressable (2.5.2)
public_suffix (>= 2.0.2, < 4.0)
backports (3.11.3)
capybara (3.4.2)
addressable
mini_mime (>= 0.1.3)
nokogiri (~> 1.8)
rack (>= 1.6.0)
rack-test (>= 0.6.3)
xpath (~> 3.1)
coderay (1.1.2)
concurrent-ruby (1.0.5)
daemons (1.2.6)
eventmachine (1.2.7)
hiredis (0.6.1)
i18n (1.0.1)
concurrent-ruby (~> 1.0)
method_source (0.9.0)
mini_mime (1.0.0)
mini_portile2 (2.3.0)
minitest (5.11.3)
multi_json (1.13.1)
mustermann (1.0.2)
nest (3.1.1)
redic
nokogiri (1.8.4)
mini_portile2 (~> 2.3.0)
ohm (3.1.1)
nest (~> 3)
redic (~> 1.5.0)
stal
pry (0.11.3)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
public_suffix (3.0.2)
rack (2.0.5)
rack-protection (2.0.3)
rack
rack-test (1.1.0)
rack (>= 1.0, < 3)
redic (1.5.0)
hiredis
shotgun (0.9.2)
rack (>= 1.0)
sinatra (2.0.3)
mustermann (~> 1.0)
rack (~> 2.0)
rack-protection (= 2.0.3)
tilt (~> 2.0)
sinatra-config-file (1.0)
sinatra-contrib
sinatra-contrib (2.0.3)
activesupport (>= 4.0.0)
backports (>= 2.8.2)
multi_json
mustermann (~> 1.0)
rack-protection (= 2.0.3)
sinatra (= 2.0.3)
tilt (>= 1.3, < 3)
slim (3.0.9)
temple (>= 0.7.6, < 0.9)
tilt (>= 1.3.3, < 2.1)
stal (0.3.0)
redic (~> 1.5)
temple (0.8.0)
thin (1.7.2)
daemons (~> 1.0, >= 1.0.9)
eventmachine (~> 1.0, >= 1.0.4)
rack (>= 1, < 3)
thread_safe (0.3.6)
tilt (2.0.8)
tzinfo (1.2.5)
thread_safe (~> 0.1)
xpath (3.1.0)
nokogiri (~> 1.8)

PLATFORMS
ruby

DEPENDENCIES
capybara
ohm
pry
shotgun
sinatra
sinatra-config-file
slim
thin

BUNDLED WITH
1.16.3
25 changes: 25 additions & 0 deletions 2230/3/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
### Описание

Веб-приложение Onliner Analyzer использует Text Analytics API от Microsoft Azure, чтобы рассчитать коэффициент доброжелательности комментариев для статей onliner.by

### Установка

1. Клонируйте или скачайте файлы проекта
2. Зайдите в папку проекта и выполните
```bash
bundle install
sudo apt-get install redis-server
```

### Первый запуск

1. Выполните в каталоге проекта:
```bash
shotgun config.ru
```

2. Откройте в браузере страницу `http://localhost:9393`

### Примечания

Azure - условно-бесплатная платформа, поэтому анализируется лишь 10 первых комментариев на статью.
11 changes: 11 additions & 0 deletions 2230/3/app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
require 'sinatra/config_file'

class ApplicationController < Sinatra::Base
set :views, Proc.new { File.join(root, "../views") }

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lint/AmbiguousBlockAssociation: Parenthesize the param Proc.new { File.join(root, "../views") } to make sure that the block will be associated with the Proc.new method call.
Style/Proc: Use proc instead of Proc.new.
Style/StringLiterals: Prefer single-quoted strings when you don't need string interpolation or special symbols.

register Sinatra::ConfigFile
config_file '../../config.yml'

get '/' do
slim :'index'

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Style/SymbolLiteral: Do not use strings for word-like symbol literals.

end
end
34 changes: 34 additions & 0 deletions 2230/3/app/controllers/articles_controller.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
require_relative './application_controller'

class ArticlesController < ApplicationController
# index - show list of articles
get '/' do
# settings.views
@articles = Article.all.sort_by(:rating).reverse!
slim :'articles/show'
end

# new - add new article
get '/new' do
slim :'articles/new'
end

post '/' do
# very simple validation
redirect 'articles' unless params[:article_new].include?('onliner.by')
html_parser = HTMLParser.new(params[:article_new])
comments_url = html_parser.run
comments = JSONParser.new(comments_url).comments
rating = AzureSender.new(comments, settings.access_key).run
article = Article.create url: params[:article_new], title: html_parser.article_title, rating: rating.sum / rating.size

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Metrics/LineLength: Line is too long. [122/120]

comments.zip(rating).each do |obj|
Comment.create(text: obj.first, rating: obj.last, article: article)
end
redirect 'articles'
end

get '/:id' do
@comments = Comment.find(article_id: params[:id])
slim :'comments/show'
end
end
47 changes: 47 additions & 0 deletions 2230/3/app/helpers/azure_sender.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
require 'uri'
require 'net/https'
require 'json'

class AzureSender
URL_TO_SERVICE = 'https://westeurope.api.cognitive.microsoft.com/text/analytics/v2.0/sentiment'.freeze
attr_reader :data, :uri, :request

def initialize(comments, api_key)
@uri = URI(URL_TO_SERVICE)
@uri.query = URI.encode_www_form({})
@data = { documents: [] }
prepare_data(comments)
@request = prepare_request(api_key)
end

def run
prepare_output_data(send_request)
end

private

def prepare_data(comments)
comments.each_with_index do |comment, index|
@data[:documents] << { 'id' => index.to_s, 'language' => 'ru', 'text' => comment }
end
end

def send_request
Net::HTTP.start(uri.host, uri.port, use_ssl: uri.scheme == 'https') do |http|
http.request(request)
end
end

def prepare_output_data(response)
JSON.parse(response.body)['documents'].map do |data|
((data['score'] * 200).to_i - 100)
end
end

# prepare data fro api
def prepare_request(api_key)
request = Net::HTTP::Post.new(uri, 'Content-Type' => 'application/json', 'Ocp-Apim-Subscription-Key' => api_key)
request.body = data.to_json
request
end
end
29 changes: 29 additions & 0 deletions 2230/3/app/helpers/html_parser.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
require 'open-uri'
require 'capybara'

class HTMLParser
COMMENTS_API_BASE_PATH = 'https://comments.api.onliner.by'.freeze
COMMENTS_COUNT = '10'.freeze
attr_reader :article_url
attr_reader :comments_url, :article_title

def initialize(article_url)
@article_url = article_url
@article_title = ''
end

def run
page = Nokogiri::HTML(open(@article_url))

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security/Open: The use of Kernel#open is a serious security risk.

@article_title = page.css('title').text
@comments_url = generate_comments_url(page.css('div#fast-comments app'))
end

private

def generate_comments_url(page)
File.join(COMMENTS_API_BASE_PATH, '/', page.at('app')['project-name'], '/', page.at('app')['entity-type'], '/', page.at('app')['entity-id'], "/comments?limit=#{COMMENTS_COUNT}")

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Metrics/LineLength: Line is too long. [181/120]

end
end

# url = HTMLParser.new('https://people.onliner.by/2018/07/26/profession', 3).run
# p url
36 changes: 36 additions & 0 deletions 2230/3/app/helpers/json_parser.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
require 'open-uri'
require 'json'

class JSONParser
attr_reader :comments_url
attr_reader :comments

def initialize(comments_url)
@comments_url = comments_url
@comments_json = []
end

def comments

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lint/DuplicateMethods: Method JSONParser#comments is defined at both 2230/3/app/helpers/json_parser.rb:6 and 2230/3/app/helpers/json_parser.rb:13.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Lint/DuplicateMethods: Method JSONParser#comments is defined at both 2230/3/app/helpers/json_parser.rb:6 and 2230/3/app/helpers/json_parser.rb:12.

#@comments_json = filter_response(send_comments_request)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Layout/LeadingCommentSpace: Missing space after #.

@comments = send_comments_request
end

private

def send_comments_request
json = open(@comments_url).read

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security/Open: The use of Kernel#open is a serious security risk.

JSON.parse(json)['comments'].map do |comment|
comment['text']
end
end

def filter_response(response)
response.map do |elem|
elem unless (elem.select {|hash,value| hash['marks'] && value['likes'] > 0}) == {}

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Layout/SpaceInsideBlockBraces: Space between { and | missing.
Layout/SpaceAfterComma: Space missing after comma.
Style/NumericPredicate: Use (value['likes']).positive? instead of value['likes'] > 0.
Layout/SpaceInsideBlockBraces: Space missing inside }.

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

NestedIterators: JSONParser#filter_response contains iterators nested 2 deep. More info.

# elem unless (res == {})
end
end
end

#content = JSONParser.new('https://comments.api.onliner.by/news/people.post/570149/comments?limit=5').comments

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Layout/LeadingCommentSpace: Missing space after #.

#p content

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Layout/LeadingCommentSpace: Missing space after #.

6 changes: 6 additions & 0 deletions 2230/3/app/models/article.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
class Article < Ohm::Model
attribute :url
attribute :title
attribute :rating
collection :comments, :Comment
end
5 changes: 5 additions & 0 deletions 2230/3/app/models/comment.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
class Comment < Ohm::Model
attribute :text
attribute :rating
reference :article, :Article
end
14 changes: 14 additions & 0 deletions 2230/3/app/views/articles/new.htm
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<html>
<head>
<meta charset="utf-8">
<title>Добавление новой статьи</title>
<head>
<body>
<p>Скопируйте URL любой статьи на onliner.by и вставьте в поле ниже</p>
<form action="http://mail.ru" method="post">
<label for="article_new">Новый URL:</label>
<input type="text" id="article_new"><br><br>
<input type="submit" value="Отправить">
</form>
<body>
</html>
20 changes: 20 additions & 0 deletions 2230/3/app/views/articles/new.slim
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
html
head
meta charset='utf-8'
title Добавление новой статьи
body
p Скопируйте URL любой статьи на onliner.by и вставьте в поле ниже
form action='../articles' method='post'
label for='article_new' Новый URL:
input type='text' name='article_new'
br
br
input type='submit' value='Отправить'

ul
li
a href='javascript:history.back()' Назад
li
a href='../articles' К списку статей
li
a href='/' На главную
35 changes: 35 additions & 0 deletions 2230/3/app/views/articles/show.htm
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<html>
<head>
<meta charset="utf-8">
<title>Список статей</title>
</head>
<body>
<h3>Список статей</h3>
<p>Выберете любую статью, чтобы увидеть на основании каких комментариев сформирован рейтинг</p>
<table border="1">
<tr>
<th>Название</th>
<th>Ссылка на источник</th>
<th>Рейтинг</th>
</tr>
<tr>
<td>
<a href="comments/1">Зубр нашёл себе тёлочку</a>
</td>
<td>
<a href="https://auto.onliner.by/2018/02/03/zubry">https://auto.onliner.by/2018/02/03/zubry</a>
</td>
<td>-53</td>
</tr>
<tr>
<td>
<a href="comments/2">Снова выросли цены на нефть</a>
</td>
<td>
<a href="https://auto.onliner.by/2018/05/25/belneftexim-6">https://auto.onliner.by/2018/05/25/belneftexim-6</a>
</td>
<td>15</td>
</tr>
</table>
</body>
</html>
Loading