frecon 0.2.2 → 0.3.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a8a2e4e957492a0168c9e814b237ea59435aa800
4
- data.tar.gz: 3051b10b6a8e7740370ffd75eebce4230b3ef252
3
+ metadata.gz: fd60a8e39df9d65354023f15a71e7ff1941465cc
4
+ data.tar.gz: 322aad2f9008ee3bac2f566a1afcc7ccc60938f8
5
5
  SHA512:
6
- metadata.gz: b579c98940cd2759ed748dbaea6b51ffeef679c6f08f958a1e7501fda4e5043e20b4fb987422ebb002b013fb679eb1ac4586a6027bfb02186b196507a0faafc7
7
- data.tar.gz: a312a6a56950302d16e0075875e25ef9b830164eb9d7999820e364fa49c5b170a72b4f7bf96ff99a2a64e7cdaca836953b9811fab42a315102586fb03014a7fd
6
+ metadata.gz: d40ef54381e9b613289a0c1b82f486a965975866e1f7e3cbe16ec15285708e05156b2bfc4c6a27a567b3ecd72fa128f379fbcbfad6b008f5ccd19f81970b559b
7
+ data.tar.gz: e6c5a2c2bbddf8de4b04441c59cc45575f76019fb2f81e3d110860b736c8ce8a6ff57203f36d6e6f92066261b52c8b5ad18d9e8052543500d158b74f352c4df2
@@ -0,0 +1,16 @@
1
+ # lib/frecon/base/bson.rb
2
+ #
3
+ # Copyright (C) 2014 Christopher Cooper, Sam Craig, Tiger Huang, Vincent Mai, Sam Mercier, and Kristofer Rye
4
+ #
5
+ # This file is part of FReCon, an API for scouting at FRC Competitions, which is
6
+ # licensed under the MIT license. You should have received a copy of the MIT
7
+ # license with this program. If not, please see
8
+ # <http://opensource.org/licenses/MIT>.
9
+
10
+ module BSON
11
+ class ObjectId
12
+ def as_json(*args)
13
+ to_s
14
+ end
15
+ end
16
+ end
@@ -8,7 +8,7 @@
8
8
  # <http://opensource.org/licenses/MIT>.
9
9
 
10
10
  module FReCon
11
- VERSION = "0.2.2"
11
+ VERSION = "0.3.0"
12
12
 
13
13
  @environment_variable = :development
14
14
 
data/lib/frecon/base.rb CHANGED
@@ -7,5 +7,6 @@
7
7
  # license with this program. If not, please see
8
8
  # <http://opensource.org/licenses/MIT>.
9
9
 
10
+ require "frecon/base/bson"
10
11
  require "frecon/base/object"
11
12
  require "frecon/base/variables"
@@ -34,44 +34,61 @@ module FReCon
34
34
  "Could not find #{model} of #{attribute} #{value}!"
35
35
  end
36
36
 
37
- # Processes a POST/PUT request and returns the post data.
38
- def self.process_json_object_request(request)
37
+ def self.process_json_request(request)
39
38
  # Rewind the request body (an IO object)
40
39
  # in case someone else has already played
41
40
  # through it.
42
41
  request.body.rewind
43
42
 
44
43
  begin
45
- # Parse the POST data as a JSON hash
46
- # (because that's what it is)
47
44
  post_data = JSON.parse(request.body.read)
48
45
  rescue JSON::ParserError => e
49
- # If we have malformed JSON (JSON::ParserError is
50
- # raised), escape out of the function.
51
46
  raise RequestError.new(400, e.message)
52
47
  end
53
48
 
54
- raise RequestError.new(422, "Must pass a JSON object!", {post_data: post_data}) if post_data.is_an?(Array)
55
49
  post_data
56
50
  end
57
51
 
58
52
  def self.create(request, params, post_data = nil)
59
- post_data ||= process_json_object_request request
53
+ post_data ||= process_json_request request
60
54
 
61
- @model = model.new
62
- @model.attributes = post_data
55
+ if post_data.is_an? Array
56
+ results = post_data.map do |post_data_item|
57
+ begin
58
+ self.create(nil, nil, post_data_item)
59
+ rescue RequestError => e
60
+ e.return_value
61
+ end
62
+ end
63
+
64
+ status_code = 201
65
+
66
+ if(results.map do |result|
67
+ result.is_an?(Array) ? result[0] : 422
68
+ end.select do |status_code|
69
+ status_code != 201
70
+ end.count > 0)
71
+
72
+ status_code = 422
73
+ end
63
74
 
64
- if @model.save
65
- [201, @model.to_json]
75
+ [status_code, results.to_json]
66
76
  else
67
- raise RequestError.new(422, @model.errors.full_messages, {params: params, post_data: post_data})
77
+ @model = model.new
78
+ @model.attributes = post_data
79
+
80
+ if @model.save
81
+ [201, @model.to_json]
82
+ else
83
+ raise RequestError.new(422, @model.errors.full_messages, {params: params, post_data: post_data})
84
+ end
68
85
  end
69
86
  end
70
87
 
71
88
  def self.update(request, params, post_data = nil)
72
89
  raise RequestError.new(400, "Must supply a #{model_name.downcase} id!") unless params[:id]
73
90
 
74
- post_data ||= process_json_object_request request
91
+ post_data ||= process_json_request request
75
92
 
76
93
  @model = find_model params
77
94
 
@@ -127,6 +144,8 @@ module FReCon
127
144
  end
128
145
 
129
146
  def self.team_number_to_team_id(post_data)
147
+ return post_data unless post_data.is_a?(Hash)
148
+
130
149
  if post_data["team_number"] && !post_data["team_id"]
131
150
  unless (team = Team.number post_data["team_number"]).nil?
132
151
  post_data["team_id"] = team.id
@@ -143,6 +162,8 @@ module FReCon
143
162
  # This supports match_number and competition_name
144
163
  # or match_number and competition (which is a Hash).
145
164
  def self.match_number_and_competition_to_match_id(post_data)
165
+ return post_data unless post_data.is_a?(Hash)
166
+
146
167
  if post_data["match_number"] && !post_data["match_id"]
147
168
  if post_data["competition_name"] && (competition = Competition.find_by name: post_data["competition_name"])
148
169
  # Try to set the match to the already existing match.
@@ -165,7 +186,7 @@ module FReCon
165
186
  post_data.delete("competition_name")
166
187
 
167
188
  post_data
168
- elsif post_data["competition"] && post_data["competition"]["_id"] && post_data["competition"]["_id"]["$oid"] && (competition = Competition.find_by(id: post_data["competition"]["_id"]["$oid"]))
189
+ elsif post_data["competition"] && post_data["competition"]["_id"] && (competition = Competition.find_by(id: post_data["competition"]["_id"]))
169
190
  # Try to set the match to the already existing match.
170
191
  match = competition.matches.find_by number: post_data["match_number"]
171
192
 
@@ -15,11 +15,23 @@ module FReCon
15
15
  def self.full(params)
16
16
  dump = {}
17
17
 
18
- Model.descendants.each do |child|
19
- dump[child.name.gsub(/FReCon::/, "").downcase.pluralize] = child.all
18
+ ordered_descendants = Model.descendants.sort_by do |model|
19
+ id_fields = model.fields.keys.select do |attribute|
20
+ attribute.ends_with?("_id") && attribute != "_id"
21
+ end
22
+
23
+ [id_fields.count, dump_compliant_name(model)]
24
+ end
25
+
26
+ ordered_descendants.each do |child|
27
+ dump[dump_compliant_name(child)] = child.all
20
28
  end
21
29
 
22
30
  dump.to_json
23
31
  end
32
+
33
+ def self.dump_compliant_name(model)
34
+ model.name.gsub(/FReCon::/, "").downcase.pluralize
35
+ end
24
36
  end
25
37
  end
@@ -9,8 +9,8 @@
9
9
 
10
10
  module FReCon
11
11
  class ParticipationsController < Controller
12
- def self.create(request, params)
13
- super(request, params, team_number_to_team_id(process_json_object_request(request)))
12
+ def self.create(request, params, post_data = nil)
13
+ super(request, params, post_data || team_number_to_team_id(process_json_request(request)))
14
14
  end
15
15
 
16
16
  def self.competition(params)
@@ -13,8 +13,8 @@ require "frecon/models"
13
13
 
14
14
  module FReCon
15
15
  class RecordsController < Controller
16
- def self.create(request, params)
17
- super(request, params, match_number_and_competition_to_match_id(team_number_to_team_id(process_json_object_request(request))))
16
+ def self.create(request, params, post_data = nil)
17
+ super(request, params, post_data || match_number_and_competition_to_match_id(team_number_to_team_id(process_json_request(request))))
18
18
  end
19
19
 
20
20
  def self.competition(params)
@@ -12,8 +12,8 @@ require "frecon/models/robot"
12
12
 
13
13
  module FReCon
14
14
  class RobotsController < Controller
15
- def self.create(request, params)
16
- super(request, params, team_number_to_team_id(process_json_object_request(request)))
15
+ def self.create(request, params, post_data = nil)
16
+ super(request, params, post_data || team_number_to_team_id(process_json_request(request)))
17
17
  end
18
18
 
19
19
  def self.competition(params)
@@ -125,6 +125,9 @@ module FReCon
125
125
  # round (Integer), optional
126
126
  # replay_number (Integer), optional
127
127
 
128
+ # Convert keys to symbols if needed.
129
+ args = Hash[args.map { |key, value| [key.to_sym, value] }]
130
+
128
131
  raise TypeError, "type must be a Symbol or String" unless args[:type].is_a?(Symbol) || args[:type].is_a?(String)
129
132
  raise ArgumentError, "type must be in #{POSSIBLE_TYPES.inspect}" unless POSSIBLE_TYPES.include?(args[:type].to_sym)
130
133
 
data/lib/frecon/model.rb CHANGED
@@ -26,6 +26,10 @@ module FReCon
26
26
  ObjectSpace.each_object(Class).select { |possibleChild| possibleChild < self }
27
27
  end
28
28
 
29
+ def self.controller
30
+ (self.name.pluralize + "Controller").constantize
31
+ end
32
+
29
33
  def no_invalid_relations
30
34
  # Get all of the belongs_to fields (ends with "_id" and not "_id" because that is the id).
31
35
  attributes.keys.select { |attribute| attribute.end_with?("_id") && attribute != "_id" }.each do |relation|
@@ -31,6 +31,8 @@ module FReCon
31
31
  when String
32
32
  Position.new(object).mongoize
33
33
  when Hash
34
+ # Convert keys to symbols if necessary.
35
+ object = Hash[object.map { |key, value| [key.to_sym, value] }]
34
36
  Position.new(object[:alliance], object[:number]).mongoize
35
37
  else
36
38
  object
@@ -45,6 +47,8 @@ module FReCon
45
47
  when String
46
48
  Position.new(object).mongoize
47
49
  when Hash
50
+ # Convert keys to symbols if necessary.
51
+ object = Hash[object.map { |key, value| [key.to_sym, value] }]
48
52
  Position.new(object[:alliance], object[:number]).mongoize
49
53
  else
50
54
  object
@@ -0,0 +1,70 @@
1
+ # lib/frecon/scraper.rb
2
+ #
3
+ # Copyright (C) 2014 Christopher Cooper, Sam Craig, Tiger Huang, Vincent Mai, Sam Mercier, and Kristofer Rye
4
+ #
5
+ # This file is part of FReCon, an API for scouting at FRC Competitions, which is
6
+ # licensed under the MIT license. You should have received a copy of the MIT
7
+ # license with this program. If not, please see
8
+ # <http://opensource.org/licenses/MIT>.
9
+
10
+ require "httparty"
11
+
12
+ module FReCon
13
+ # The default scraper scrapes other FReCon instances.
14
+ # To scrape a different source, a descendant scraper should be used.
15
+ class Scraper
16
+ def initialize(base_uri)
17
+ @base_uri = base_uri
18
+ end
19
+
20
+ # Reads and imports a data string.
21
+ # Determines what to do with information in the `context` hash.
22
+ def read(data, context = {})
23
+ # `data` will be a string, so we need to convert it from JSON.
24
+ data = JSON.parse(data)
25
+
26
+ # Here we want `context` to tell us what model we are making.
27
+ if context[:model]
28
+ result = context[:model].controller.create(nil, nil, data)
29
+ result.first == 201 ? result.first : JSON.parse(result.last)
30
+ else
31
+ # Therefore, we must be dealing with a dump.
32
+ statuses = data.map do |key, value|
33
+ begin
34
+ unless value.empty?
35
+ model = ("FReCon::" + key.singularize.capitalize).constantize
36
+ result = model.controller.create(nil, nil, value)
37
+ result.first == 201 ? result.first : JSON.parse(result.last)
38
+ end
39
+ rescue Moped::Errors::OperationFailure => e
40
+ RequestError.new(422, "A model already exists in your database with the key you are trying to import.\nPerhaps you should clear your database?").return_value
41
+ end
42
+ end
43
+ statuses.delete(nil)
44
+ statuses
45
+ end
46
+ end
47
+
48
+ # If no arguments are passed, will import the whole other database.
49
+ # If only one argument is passed, will import all of that model.
50
+ # If two arguments are passed, will import the models that match
51
+ # the query params.
52
+ def get(model = nil, query = {})
53
+ # Turns something like "team" into Team.
54
+ model = ("FReCon::" + model.capitalize).constantize if model.is_a?(String)
55
+
56
+ # The route name for the model branch.
57
+ route_name = model.name.gsub(/FReCon::/, "").downcase.pluralize if model
58
+
59
+ if !model && query.empty?
60
+ data = HTTParty.get("http://#{@base_uri}:4567/dump")
61
+ elsif model && query.empty?
62
+ data = HTTParty.get("http://#{@base_uri}:4567/#{route_name}")
63
+ else
64
+ data = HTTParty.get("http://#{@base_uri}:4567/#{route_name}", { query: query })
65
+ end
66
+
67
+ read data.body, model: model
68
+ end
69
+ end
70
+ end
@@ -0,0 +1,10 @@
1
+ # lib/frecon/scrapers.rb
2
+ #
3
+ # Copyright (C) 2014 Christopher Cooper, Sam Craig, Tiger Huang, Vincent Mai, Sam Mercier, and Kristofer Rye
4
+ #
5
+ # This file is part of FReCon, an API for scouting at FRC Competitions, which is
6
+ # licensed under the MIT license. You should have received a copy of the MIT
7
+ # license with this program. If not, please see
8
+ # <http://opensource.org/licenses/MIT>.
9
+
10
+ require "frecon/scraper"
data/lib/frecon/server.rb CHANGED
@@ -22,6 +22,7 @@ module FReCon
22
22
  end
23
23
 
24
24
  def self.run!
25
+ set :environment, FReCon.environment
25
26
  Database.setup(FReCon.environment)
26
27
 
27
28
  super
data/lib/frecon.rb CHANGED
@@ -7,8 +7,12 @@
7
7
  # license with this program. If not, please see
8
8
  # <http://opensource.org/licenses/MIT>.
9
9
 
10
+ require "mongoid"
11
+
10
12
  require "frecon/base"
11
13
 
12
14
  require "frecon/database"
13
15
  require "frecon/server"
14
16
  require "frecon/console"
17
+
18
+ require "frecon/scrapers"
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: frecon
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.2
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Sam Craig
@@ -57,6 +57,20 @@ dependencies:
57
57
  - - "~>"
58
58
  - !ruby/object:Gem::Version
59
59
  version: '4.0'
60
+ - !ruby/object:Gem::Dependency
61
+ name: httparty
62
+ requirement: !ruby/object:Gem::Requirement
63
+ requirements:
64
+ - - "~>"
65
+ - !ruby/object:Gem::Version
66
+ version: '0.13'
67
+ type: :runtime
68
+ prerelease: false
69
+ version_requirements: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - "~>"
72
+ - !ruby/object:Gem::Version
73
+ version: '0.13'
60
74
  description: A JSON API for scouting FRC competitions that manages the database for
61
75
  the user.
62
76
  email: frc-frecon@googlegroups.com
@@ -68,6 +82,7 @@ files:
68
82
  - bin/frecon
69
83
  - lib/frecon.rb
70
84
  - lib/frecon/base.rb
85
+ - lib/frecon/base/bson.rb
71
86
  - lib/frecon/base/object.rb
72
87
  - lib/frecon/base/variables.rb
73
88
  - lib/frecon/console.rb
@@ -94,6 +109,8 @@ files:
94
109
  - lib/frecon/position.rb
95
110
  - lib/frecon/request_error.rb
96
111
  - lib/frecon/routes.rb
112
+ - lib/frecon/scraper.rb
113
+ - lib/frecon/scrapers.rb
97
114
  - lib/frecon/server.rb
98
115
  homepage: https://github.com/frc-frecon/frecon
99
116
  licenses: