find_deals 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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