find_deals 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,5 @@
1
+ development:
2
+ adapter: sqlite3
3
+ database: db/saved_deals.sqlite3
4
+ pool: 5
5
+ timeout: 5000
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+ require "require_all"
3
+
4
+ require "nokogiri"
5
+ require "open-uri"
6
+ require "rake"
7
+ require "pry"
8
+ require 'active_record'
9
+ require 'sinatra/activerecord'
10
+
11
+
12
+
13
+ require_all "lib" #load up all files in the lib directory and its subdirectories
14
+
15
+ # connection to sqlite database here. creates the deals.sqlite database when running migrate
16
+ # We havew active record installed
17
+ connection_details = YAML::load(File.open('config/database.yml'))
18
+ ActiveRecord::Base.establish_connection(:development)
19
+
20
+
21
+
22
+
23
+
24
+
25
+
@@ -0,0 +1,17 @@
1
+ class SaveDeals < ActiveRecord::Migration[5.2]
2
+
3
+ def change
4
+ create_table :saved_deals do |d|
5
+ d.string :title
6
+ d.string :url
7
+ d.string :location
8
+ d.integer :price
9
+ d.integer :promotion
10
+ d.string :about
11
+ end
12
+ add_foreign_key :saved_deals, :users
13
+ add_foreign_key :saved_deals, :categories
14
+ add_foreign_key :saved_deals, :cities
15
+ end
16
+ end
17
+
@@ -0,0 +1,16 @@
1
+ class Categories < ActiveRecord::Migration[5.2]
2
+ def change
3
+ create_table :categories do |c|
4
+ c.string :name
5
+ end
6
+ end
7
+
8
+ # FindDeals::Cities.create(name: nil)
9
+ # FindDeals::Cities.create(name: "dining")
10
+ # FindDeals::Cities.create(name: "wellness-beauty")
11
+ # FindDeals::Cities.create(name: "activities")
12
+ # FindDeals::Cities.create(name: "shopping")
13
+ # FindDeals::Cities.create(name: "services")
14
+ # FindDeals::Cities.create(name: "wine")
15
+ # FindDeals::Cities.create(name: "personalised-gifts")
16
+ end
@@ -0,0 +1,8 @@
1
+ class Cities < ActiveRecord::Migration[5.2]
2
+ def change
3
+ create_table :cities do |c|
4
+ c.string :name
5
+ end
6
+ end
7
+
8
+ end
@@ -0,0 +1,11 @@
1
+ # db/migrate/01_create_artists.rb
2
+
3
+ class Users < ActiveRecord::Migration[5.2]
4
+
5
+ def change
6
+ create_table :users do |u|
7
+ u.string :name
8
+ end
9
+ end
10
+ end
11
+
@@ -0,0 +1,8 @@
1
+ # db/migrate/01_create_artists.rb
2
+
3
+ class AddUserToDeals < ActiveRecord::Migration[5.2]
4
+
5
+ def change
6
+ add_column :saved_deals, :user_id, :integer
7
+ end
8
+ end
@@ -0,0 +1,6 @@
1
+ class AddCityToDeals < ActiveRecord::Migration[5.2]
2
+
3
+ def change
4
+ add_column :saved_deals, :city_id, :integer
5
+ end
6
+ end
@@ -0,0 +1,6 @@
1
+ class AddCategoryToDeals < ActiveRecord::Migration[5.2]
2
+
3
+ def change
4
+ add_column :saved_deals, :category_id, :integer
5
+ end
6
+ end
Binary file
data/db/schema.rb ADDED
@@ -0,0 +1,39 @@
1
+ # This file is auto-generated from the current state of the database. Instead
2
+ # of editing this file, please use the migrations feature of Active Record to
3
+ # incrementally modify your database, and then regenerate this schema definition.
4
+ #
5
+ # Note that this schema.rb definition is the authoritative source for your
6
+ # database schema. If you need to create the application database on another
7
+ # system, you should be using db:schema:load, not running all the migrations
8
+ # from scratch. The latter is a flawed and unsustainable approach (the more migrations
9
+ # you'll amass, the slower it'll run and the greater likelihood for issues).
10
+ #
11
+ # It's strongly recommended that you check this file into your version control system.
12
+
13
+ ActiveRecord::Schema.define(version: 7) do
14
+
15
+ create_table "categories", force: :cascade do |t|
16
+ t.string "name"
17
+ end
18
+
19
+ create_table "cities", force: :cascade do |t|
20
+ t.string "name"
21
+ end
22
+
23
+ create_table "saved_deals", force: :cascade do |t|
24
+ t.string "title"
25
+ t.string "url"
26
+ t.string "location"
27
+ t.integer "price"
28
+ t.integer "promotion"
29
+ t.string "about"
30
+ t.integer "user_id"
31
+ t.integer "city_id"
32
+ t.integer "category_id"
33
+ end
34
+
35
+ create_table "users", force: :cascade do |t|
36
+ t.string "name"
37
+ end
38
+
39
+ end
data/db/seeds.rb ADDED
@@ -0,0 +1,15 @@
1
+ Cities.find_or_create_by(name: "sydney")
2
+ Cities.find_or_create_by(name: "melbourne")
3
+ Cities.find_or_create_by(name: "perth")
4
+ Cities.find_or_create_by(name: "brisbane")
5
+ Cities.find_or_create_by(name: "adelaide")
6
+ Cities.find_or_create_by(name: "gold-coast")
7
+
8
+ Categories.find_or_create_by(name: nil)
9
+ Categories.find_or_create_by(name: "dining")
10
+ Categories.find_or_create_by(name: "wellness-beauty")
11
+ Categories.find_or_create_by(name: "activities")
12
+ Categories.find_or_create_by(name: "shopping")
13
+ Categories.find_or_create_by(name: "services")
14
+ Categories.find_or_create_by(name: "wine")
15
+ Categories.find_or_create_by(name: "personalised-gifts")
@@ -0,0 +1,42 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "lib/find_deals/version"
4
+
5
+ Gem::Specification.new do |spec|
6
+ spec.name = "find_deals"
7
+ spec.version = FindDeals::VERSION
8
+ spec.authors = ["nils-vanderwerf"]
9
+ spec.email = ["n.vanderw.92@gmail.com"]
10
+
11
+ spec.summary = "A Web scraper for Scoopon to find deals and promotions"
12
+ spec.description = "Based on the users city and category input, they scrape a list of deals from Scoopon.com. They have they chhoice to save to the database and view their saved deals."
13
+ spec.homepage = "https://github.com/nils-vanderwerf/find_deals/"
14
+ spec.license = "MIT"
15
+ spec.required_ruby_version = Gem::Requirement.new(">= 2.4.0")
16
+
17
+ spec.metadata["homepage_uri"] = spec.homepage
18
+ spec.metadata["source_code_uri"] = "https://github.com/nils-vanderwerf/find_deals"
19
+ spec.metadata["changelog_uri"] = "https://github.com/nils-vanderwerf/find_deals/blob/master/CHANGELOG.md"
20
+
21
+ # Specify which files should be added to the gem when it is released.
22
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
23
+ spec.files = Dir.chdir(File.expand_path(__dir__)) do
24
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{\A(?:test|spec|features)/}) }
25
+ end
26
+ spec.bindir = "exe"
27
+ spec.executables = spec.files.grep(%r{\Aexe/}) { |f| File.basename(f) }
28
+ spec.require_paths = ["lib"]
29
+
30
+ spec.add_dependency "nokogiri"
31
+ spec.add_dependency "require_all"
32
+ spec.add_dependency "activerecord"
33
+ spec.add_dependency "sinatra-activerecord"
34
+ spec.add_dependency "sqlite3"
35
+
36
+
37
+ spec.add_development_dependency "bundler", "~> 2.2.11"
38
+ spec.add_development_dependency "rake", "~> 10.0"
39
+
40
+ spec.add_development_dependency "pry"
41
+
42
+ end
data/lib/find_deals.rb ADDED
@@ -0,0 +1,13 @@
1
+ require_relative "./find_deals/version"
2
+
3
+ module FindDeals
4
+ class Error < StandardError; end
5
+
6
+ # def print
7
+ # puts "===================================================================="
8
+ # puts "#{self.title.upcase}"
9
+ # puts "#{self.location}"
10
+ # puts "#{self.price} - #{self.promotion.upcase}"
11
+ # puts "===================================================================="
12
+ # end
13
+ end
@@ -0,0 +1,3 @@
1
+ class Categories < ActiveRecord::Base
2
+ has_many :saved_deals
3
+ end
@@ -0,0 +1,3 @@
1
+ class Cities < ActiveRecord::Base
2
+ has_many :saved_deals
3
+ end
@@ -0,0 +1,353 @@
1
+
2
+ class FindDeals::CLI
3
+ attr_accessor :city_input, :category_input, :input, :user_name, :selected_deal
4
+
5
+ def initialize
6
+ # @deals = FindDeals::SavedDeals.all
7
+ @user_name = ""
8
+ @input = ""
9
+ @city_input = ""
10
+ @category_input = ""
11
+ @selected_deal
12
+ end
13
+
14
+ def call
15
+ puts "--------------------------------------------------------------------"
16
+ puts ""
17
+ puts "Welcome to this amazing promo finder!"
18
+ puts ""
19
+ start
20
+ end
21
+
22
+ def start
23
+ #-----LIST OF METHODS---#
24
+ prompt_user_city
25
+ prompt_user_category
26
+ if FindDeals::Deal.all.length != 0
27
+ print_deals
28
+ print_more_info
29
+ prompt_to_save_deal
30
+ prompt_to_show_saved_deals
31
+ next_steps
32
+ else
33
+ start
34
+ end
35
+ end
36
+
37
+ def prompt_user_city
38
+ puts "--------------------------------------------------------------------"
39
+ puts ""
40
+ puts "Select a city (type in corresponding number)"
41
+ puts ""
42
+ puts <<-DOC
43
+ 1. Sydney
44
+ 2. Melbourne
45
+ 3. Perth
46
+ 4. Brisbane
47
+ 5. Adelaide
48
+ 6. Gold Coast
49
+ DOC
50
+
51
+ puts ""
52
+ get_city_input
53
+ end
54
+
55
+ def get_city_input
56
+ @input = gets.strip
57
+ @input != 'quit' ? @city_input = select_city_from_input : goodbye
58
+ end
59
+
60
+ def select_city_from_input
61
+ while @input.to_i == 0 || @input.to_i > Cities.all.size
62
+ invalid_input
63
+ prompt_user_city
64
+ end
65
+ Cities.find(@input).name # Collects it from the database
66
+ end
67
+
68
+ def select_category_from_input
69
+ while @input.to_i == 0 || @input.to_i > Categories.all.size
70
+ invalid_input
71
+ prompt_user_category
72
+ end
73
+ Categories.find(@input).name ## Collects it from the database
74
+ end
75
+
76
+ def prompt_user_category
77
+ puts "----------------------------------------------------------------"
78
+ puts ""
79
+ puts "Select a category (type in corresponding number)"
80
+ puts "Type quit to exit the program"
81
+ puts <<-DOC
82
+ 1. Anything
83
+ 2. Dining
84
+ 3. Wellness & Beauty
85
+ 4. Activities
86
+ 5. Shopping
87
+ 6. Services
88
+ 7. Wine
89
+ 8. Personalised Gifts
90
+ DOC
91
+ puts ""
92
+ get_category_input
93
+ end
94
+
95
+ def get_category_input
96
+ @input = gets.strip
97
+ @category_input = select_category_from_input
98
+ if @input == 'quit'
99
+ goodbye
100
+ end
101
+
102
+ if @input.to_i == 0 || @input.to_i > Categories.all.length
103
+ invalid_input
104
+ get_category_input
105
+ end
106
+ @category_input = Categories.find(input).name
107
+ site_scraper = FindDeals::Scraper.new(@city_input, @category_input)
108
+ if FindDeals::Deal.all.length == 0
109
+ puts "--------------------------------------------------------------------"
110
+ puts ""
111
+ puts "Sorry! No deals for this selection today. Please try another selection."
112
+ puts ""
113
+ puts "--------------------------------------------------------------------"
114
+ end
115
+ end
116
+
117
+ def print_deals
118
+ puts "--------------------------------------------------------------------"
119
+ puts ""
120
+ puts "DEALS FOR THIS INPUT"
121
+ puts ""
122
+ FindDeals::Deal.all.each.with_index(1) do |deal, index|
123
+ puts "#{index}."
124
+ puts deal.print
125
+ end
126
+ end
127
+
128
+ def print_more_info
129
+ if FindDeals::Deal.all.length != 0
130
+ puts "--------------------------------------------------------------------"
131
+ puts ""
132
+ puts "Please enter the number of the deal you'd like to see more about. Type in quit to exit"
133
+ puts ""
134
+ @input = gets.strip.to_i
135
+ while @input == 0 || @input > FindDeals::Deal.all.size
136
+ invalid_input
137
+ @input = gets.strip.to_i
138
+ end
139
+ FindDeals::Deal.all[@input - 1].print_about_details
140
+ @selected_deal = FindDeals::Deal.all[@input - 1]
141
+ else
142
+ puts "--------------------------------------------------------------------"
143
+ puts ""
144
+ puts "Sorry! No deals for this selection today. Please try another selection."
145
+ puts ""
146
+ puts "--------------------------------------------------------------------"
147
+ end
148
+
149
+ if @input == 'quit'
150
+ goodbye
151
+ end
152
+ end
153
+
154
+ def prompt_to_save_deal
155
+ puts ""
156
+ puts "Would you like to save this deal? Y or N"
157
+ @input = gets.strip.downcase
158
+ puts ""
159
+ puts "--------------------------------------------------------------------"
160
+ if @input == "y"
161
+ user = get_user
162
+ puts "Saving deal..."
163
+ puts ""
164
+ puts "--------------------------------------------------------------------"
165
+
166
+ @selected_deal.save(user.id) ##save to Saved Deals, with the user id as the User_id
167
+ elsif @input == "n"
168
+ next_steps
169
+ elsif @input == 'quit'
170
+ goodbye
171
+ else
172
+ invalid_input
173
+ prompt_to_save_deal
174
+ end
175
+ end
176
+
177
+ def get_user
178
+ puts "--------------------------------------------------------------------"
179
+ puts ""
180
+ puts "We need to be able to associate this deal with you."
181
+ puts "Please enter a username"
182
+ @input = gets.strip
183
+ if @input == 'quit'
184
+ goodbye
185
+ else
186
+ puts "--------------------------------------------------------------------"
187
+ @user_name = input
188
+ Users.find_or_create_by(name: @user_name)
189
+ end
190
+ end
191
+
192
+ def prompt_to_show_saved_deals
193
+ puts ""
194
+ puts "Would you like to see your saved deals? Y or N"
195
+
196
+ @input = gets.strip.downcase
197
+ puts ""
198
+ puts "--------------------------------------------------------------------"
199
+
200
+ if @input == "y"
201
+ show_saved_deals
202
+ elsif @input == "n"
203
+ next_steps
204
+ elsif @input == 'quit'
205
+ goodbye
206
+ else
207
+ invalid_input
208
+ prompt_to_show_saved_deals
209
+ end
210
+
211
+ end
212
+
213
+ def show_saved_deals
214
+ puts ""
215
+ puts "--------------------------------------------------------------------"
216
+ puts ""
217
+ puts "YOUR SAVED DEALS"
218
+ puts ""
219
+ puts "--------------------------------------------------------------------"
220
+ #get id of selected_user
221
+ user = Users.find_by(name: @user_name)
222
+ deals_from_user = SavedDeals.select {|deal| deal.user_id == user.id}
223
+ deals_from_user.each.with_index(1) do |deal, index|
224
+ puts "#{index}."
225
+ puts deal.print
226
+ end
227
+ end
228
+
229
+ def filter_by_city
230
+ puts ""
231
+ puts "--------------------------------------------------------------------"
232
+ puts ""
233
+ puts "YOUR SAVED DEALS IN #{city_input.upcase.split('-').join(' ')}"
234
+ puts ""
235
+ puts "--------------------------------------------------------------------"
236
+ #get id of selected_user
237
+ user = Users.find_by(name: @user_name)
238
+ deals_from_city = SavedDeals.select {|deal| deal.user_id == user.id && deal.city_id == @input.to_i}
239
+ if deals_from_city.length == 0
240
+ puts "Sorry! No saved deals for this section. Please try another selection."
241
+ next_steps
242
+ end
243
+ deals_from_city.each.with_index(1) do |deal, index|
244
+ puts "#{index}."
245
+ puts deal.print
246
+ end
247
+ end
248
+
249
+ def filter_by_category
250
+ puts ""
251
+ puts "--------------------------------------------------------------------"
252
+ puts ""
253
+ puts "YOUR SAVED DEALS IN THE #{@category_input == nil ? 'ALL DEALS' : @category_input.upcase.split('-').join(' ')} CATEGORY"
254
+ puts ""
255
+ puts "--------------------------------------------------------------------"
256
+ #get id of selected_user
257
+ user = Users.find_by(name: @user_name)
258
+ deals_from_category = SavedDeals.select {|deal| deal.user_id == user.id && deal.category_id == @input.to_i}
259
+ if deals_from_category.length == 0
260
+ puts "Sorry! No saved deals for this section. Please try another selection."
261
+ next_steps
262
+ end
263
+ deals_from_category.each.with_index(1) do |deal, index|
264
+ puts "#{index}."
265
+ puts deal.print
266
+ end
267
+
268
+ end
269
+
270
+ def next_steps
271
+ puts "--------------------------------------------------------------------"
272
+ puts ""
273
+ puts "What would you like to do now"
274
+ puts "- To view more deals, type 'MORE'"
275
+ puts "- To filter your saved deals by city, type in 'CITY'"
276
+ puts "- To filter your saved deals by category, type in 'CATEGORY'"
277
+ puts "- To delete a saved deal type 'DELETE'"
278
+ puts "- To quit, type in quit"
279
+ @input = gets.strip.downcase
280
+
281
+ if @input == "more"
282
+ puts ""
283
+ puts "--------------------------------------------------------------------"
284
+ # start program again
285
+ start #
286
+ elsif @input == 'city'
287
+ puts ""
288
+ puts "--------------------------------------------------------------------"
289
+ prompt_user_city
290
+ filter_by_city
291
+ next_steps
292
+ elsif @input == 'category'
293
+ prompt_user_category
294
+ filter_by_category
295
+ next_steps
296
+ elsif @input == "delete"
297
+ delete_record
298
+ next_steps
299
+ elsif @input == "quit"
300
+ goodbye
301
+ else
302
+ invalid_input
303
+ next_steps
304
+ end
305
+ end
306
+
307
+ def delete_record
308
+ user = get_user
309
+ show_saved_deals
310
+ puts "--------------------------------------------------------------------"
311
+ puts ""
312
+ puts "Type in the number of the deal you would like to delete"
313
+ puts ""
314
+ puts "--------------------------------------------------------------------"
315
+ @input = gets.strip.downcase
316
+
317
+ while @input.to_i == 0 || @input.to_i >= SavedDeals.select {|deal| deal.user_id == user.id}.length
318
+ invalid_input
319
+ puts "--------------------------------------------------------------------"
320
+ puts ""
321
+ puts "Type in the number of the deal you would like to delete"
322
+ puts ""
323
+ puts "--------------------------------------------------------------------"
324
+ @input = gets.strip.downcase
325
+
326
+ if @input == 'quit'
327
+ goodbye
328
+ end
329
+ end
330
+
331
+ SavedDeals.all.delete_from_db(@input.to_i)
332
+ prompt_to_show_saved_deals
333
+ next_steps
334
+
335
+ end
336
+
337
+ def invalid_input
338
+ puts "--------------------------------------------------------------------"
339
+ puts ""
340
+ puts "Invalid input. Please try again"
341
+ puts ""
342
+ puts "--------------------------------------------------------------------"
343
+ end
344
+
345
+ def goodbye
346
+ puts "--------------------------------------------------------------------"
347
+ puts ""
348
+ puts "Hope to see you again soon for more deals!"
349
+ puts ""
350
+ puts "--------------------------------------------------------------------"
351
+ exit
352
+ end
353
+ end