diff --git a/Pearlception/Gemfile b/Pearlception/Gemfile index e4b3cfc..07f5318 100644 --- a/Pearlception/Gemfile +++ b/Pearlception/Gemfile @@ -20,7 +20,8 @@ gem 'uglifier', '>= 1.3.0' gem 'coffee-rails', '~> 4.2' # See https://github.com/rails/execjs#readme for more supported runtimes # gem 'therubyracer', platforms: :ruby - +gem 'chart-js-rails' +gem 'jquery-ui-rails' # Use jquery as the JavaScript library gem 'jquery-rails' # Turbolinks makes navigating your web application faster. Read more: https://github.com/turbolinks/turbolinks diff --git a/Pearlception/Gemfile.lock b/Pearlception/Gemfile.lock index eb8e8fc..3370f70 100644 --- a/Pearlception/Gemfile.lock +++ b/Pearlception/Gemfile.lock @@ -53,6 +53,8 @@ GEM bootstrap-popover-rails (0.1.0) builder (3.2.2) byebug (9.0.6) + chart-js-rails (0.1.2) + railties (> 3.1) coderay (1.1.1) coffee-rails (4.2.1) coffee-script (>= 2.2.0) @@ -87,6 +89,8 @@ GEM rails-dom-testing (>= 1, < 3) railties (>= 4.2.0) thor (>= 0.14, < 2.0) + jquery-ui-rails (6.0.1) + railties (>= 3.2.16) kaminari (1.0.1) activesupport (>= 4.1.0) kaminari-actionview (= 1.0.1) @@ -215,6 +219,7 @@ DEPENDENCIES bcrypt (~> 3.1.7) bootstrap-popover-rails byebug + chart-js-rails coffee-rails (~> 4.2) devise high_voltage (~> 3.0.0) @@ -222,6 +227,7 @@ DEPENDENCIES hirb-unicode jbuilder (~> 2.5) jquery-rails + jquery-ui-rails kaminari listen (~> 3.0.5) mysql2 (>= 0.3.18, < 0.5) diff --git a/Pearlception/app/assets/javascripts/application.js b/Pearlception/app/assets/javascripts/application.js index fe47c91..1f319ca 100644 --- a/Pearlception/app/assets/javascripts/application.js +++ b/Pearlception/app/assets/javascripts/application.js @@ -15,3 +15,5 @@ //= require turbolinks //= require bootstrap/bootstrap-rails-tooltip //= require bootstrap/bootstrap-rails-popover +//= require Chart +//= require jquery-ui diff --git a/Pearlception/app/assets/javascripts/dashboard.coffee b/Pearlception/app/assets/javascripts/dashboard.coffee deleted file mode 100644 index 24f83d1..0000000 --- a/Pearlception/app/assets/javascripts/dashboard.coffee +++ /dev/null @@ -1,3 +0,0 @@ -# Place all the behaviors and hooks related to the matching controller here. -# All this logic will automatically be available in application.js. -# You can use CoffeeScript in this file: http://coffeescript.org/ diff --git a/Pearlception/app/assets/javascripts/dashboard.js b/Pearlception/app/assets/javascripts/dashboard.js new file mode 100644 index 0000000..e69de29 diff --git a/Pearlception/app/assets/javascripts/statistics.js b/Pearlception/app/assets/javascripts/statistics.js new file mode 100644 index 0000000..1911156 --- /dev/null +++ b/Pearlception/app/assets/javascripts/statistics.js @@ -0,0 +1,102 @@ +/* +Set up both the datepicker tabs with this +*/ +$('#from_datepicker').datepicker() +$('#to_datepicker').datepicker() + +$('#dateFilterButton').on('click',function(){ + var fromDate = $('#from_datepicker')[0].value; + var toDate = $('#to_datepicker')[0].value; + var queryString = ""; + if(fromDate != "" && toDate != ""){ + queryString = "statistics.json/?from_date="+encodeURI(fromDate)+"&to_date="+encodeURI(toDate); + } + else{ + queryString = "statistics.json" + } + $.get(queryString, function(gradeData){ + constructGradesGraph(gradeData); + }) +}); + +$(document).ready( + $.get("statistics.json", function(gradeData){ + constructGradesGraph(gradeData); + }) +) + +function constructGradesGraph(gradeData){ + console.log(gradeData) + var labels = generateLabels(gradeData); + var colors = generateColors(gradeData); + var gradeCounts = getGradeCounts(labels, gradeData); + var ctx = document.getElementById("gradesChart"); + var myChart = new Chart(ctx, { + type: 'bar', + data: { + labels: labels, + datasets: [{ + label: 'Count for each grade', + data: gradeCounts, + backgroundColor: colors, + borderColor: colors, + borderWidth: 1 + }] + }, + options: { + scales: { + yAxes: [{ + ticks: { + beginAtZero:true + } + }] + } + } + }); +} + +function getGradeCounts(labels, gradeData){ + var counts = initCountArray(labels); + var oysters = gradeData.allOysters; + for(var i = 0; i < oysters.length; i++){ + var grade = oysters[i].grade; + counts[labels.indexOf(grade)]++; + } + console.log(counts); + return counts; +} + +function initCountArray(labels){ + counts = []; + for(var i = 0; i < labels.length; i++){ + counts.push(0) + } + return counts; +} + +function generateLabels(gradeData){ + let grades = gradeData.grades; + labels = []; + for(var i = 0; i < grades.length; i++){ + labels.push(grades[i].Full_name) + } + return labels; +} + +function generateColors(gradeData){ + colors = []; + availableColors = [ + 'rgba(255, 99, 132, 0.2)', + 'rgba(54, 162, 235, 0.2)', + 'rgba(255, 206, 86, 0.2)', + 'rgba(75, 192, 192, 0.2)', + 'rgba(153, 102, 255, 0.2)', + 'rgba(255, 159, 64, 0.2)' + ]; + for(var i = 0; i < gradeData.grades.length; i++){ + var index = Math.round(Math.random() * (availableColors.length - 1)); + var color = availableColors[index] + colors.push(color); + } + return colors; +} \ No newline at end of file diff --git a/Pearlception/app/assets/stylesheets/application.css b/Pearlception/app/assets/stylesheets/application.css index a75d597..8b971c4 100644 --- a/Pearlception/app/assets/stylesheets/application.css +++ b/Pearlception/app/assets/stylesheets/application.css @@ -14,4 +14,5 @@ *= require_self *= require bootstrap/bootstrap-rails-tooltip *= require bootstrap/bootstrap-rails-popover + *= require jquery-ui */ diff --git a/Pearlception/app/assets/stylesheets/statistics.scss b/Pearlception/app/assets/stylesheets/statistics.scss new file mode 100644 index 0000000..b05be63 --- /dev/null +++ b/Pearlception/app/assets/stylesheets/statistics.scss @@ -0,0 +1,7 @@ +// Place all the styles related to the statistics controller here. +// They will automatically be included in application.css. +// You can use Sass (SCSS) here: http://sass-lang.com/ +#myChart{ + width:100%; + height: 100%; +} diff --git a/Pearlception/app/controllers/dashboard_controller.rb b/Pearlception/app/controllers/dashboard_controller.rb index 02d741b..e51857e 100644 --- a/Pearlception/app/controllers/dashboard_controller.rb +++ b/Pearlception/app/controllers/dashboard_controller.rb @@ -8,7 +8,8 @@ class DashboardController < ApplicationController puts params @results = Hash.new names = (Company.pluck :company_name) - ["IVA"] - names.map!{|tenant| tenant.gsub(/'/,'').gsub(/\s/,'')} + binding.pry + names.map!{|tenant| tenant.gsub(/'/,'').gsub(/\s/,'')} names.each do |name| @@ -32,4 +33,8 @@ class DashboardController < ApplicationController redirect_to "/signin" unless user_signed_in? end + def statistics + + end + end diff --git a/Pearlception/app/controllers/statistics_controller.rb b/Pearlception/app/controllers/statistics_controller.rb new file mode 100644 index 0000000..10b2ce4 --- /dev/null +++ b/Pearlception/app/controllers/statistics_controller.rb @@ -0,0 +1,25 @@ +class StatisticsController < ApplicationController + + def index + if params[:from_date] != nil && params[:to_date] != nil + from_date = Date.strptime(params[:from_date], '%m/%d/%Y') + to_date = Date.strptime(params[:to_date], '%m/%d/%Y') + runs = Run.where(:runDate => from_date.beginning_of_day..to_date.end_of_day) + else + runs = Run.all + end + puts runs.inspect + oysterData = [] + all_oysters = [] + runs.each do |run| + oysters = Oyster.where(run_id: run.id).to_a + data = {"run": run, "oysters": oysters} + oysterData.push(data) + all_oysters.concat(oysters) + end + respond_to do |f| + f.html + f.json {render :json => {grades:Grade.all,oysterData:oysterData,allOysters:all_oysters}} + end + end +end diff --git a/Pearlception/app/helpers/statistics_helper.rb b/Pearlception/app/helpers/statistics_helper.rb new file mode 100644 index 0000000..2d25d41 --- /dev/null +++ b/Pearlception/app/helpers/statistics_helper.rb @@ -0,0 +1,2 @@ +module StatisticsHelper +end diff --git a/Pearlception/app/views/dashboard/index.html.erb b/Pearlception/app/views/dashboard/index.html.erb index 21783b8..87791de 100644 --- a/Pearlception/app/views/dashboard/index.html.erb +++ b/Pearlception/app/views/dashboard/index.html.erb @@ -40,6 +40,7 @@ <% if current_user.admin? %>
  • Companies
  • <% else %> +
  • Statistics
  • Grades
  • <% end %> + +
  • + <%= link_to(destroy_user_session_path, class: 'logout-link', :method => :delete) do %> + Logout + <% end %> +
  • + + + + + + +
    +
    + +
    +
    +
    +
    +
    +

    From:

    +
    +
    +

    To:

    +
    +
    + +
    +
    +
    +
    +
    +
    + +
    +
    +
    + <%= javascript_include_tag "statistics.js" %> + <%= javascript_include_tag "bootstrap.min" %>_ + diff --git a/Pearlception/config/initializers/assets.rb b/Pearlception/config/initializers/assets.rb index 3417571..d81e3b7 100644 --- a/Pearlception/config/initializers/assets.rb +++ b/Pearlception/config/initializers/assets.rb @@ -2,7 +2,7 @@ # Version of your assets, change this if you want to expire all your assets. Rails.application.config.assets.version = '1.0' -Rails.application.config.assets.precompile += %w(bootstrap.css styles.css.erb bootstrap.min.js runs.js dashboard.css) +Rails.application.config.assets.precompile += %w( statistics.js bootstrap.css styles.css.erb bootstrap.min.js runs.js dashboard.css) # Add additional assets to the asset load path # Rails.application.config.assets.paths << Emoji.images_path diff --git a/Pearlception/config/routes.rb b/Pearlception/config/routes.rb index 5d5249b..552c88d 100644 --- a/Pearlception/config/routes.rb +++ b/Pearlception/config/routes.rb @@ -10,7 +10,7 @@ Rails.application.routes.draw do resources :runs resources :companies resources :grades - + resources :statistics devise_for :users, :controllers => {:registrations => 'registrations', :sessions => 'sessions'} #devise_for :users, controllers: {:sessions => 'session'} devise_scope :users do diff --git a/Pearlception/test/controllers/statistics_controller_test.rb b/Pearlception/test/controllers/statistics_controller_test.rb new file mode 100644 index 0000000..e2e12b8 --- /dev/null +++ b/Pearlception/test/controllers/statistics_controller_test.rb @@ -0,0 +1,7 @@ +require 'test_helper' + +class StatisticsControllerTest < ActionDispatch::IntegrationTest + # test "the truth" do + # assert true + # end +end diff --git a/init/apartment.rb b/init/apartment.rb new file mode 100644 index 0000000..1956469 --- /dev/null +++ b/init/apartment.rb @@ -0,0 +1,91 @@ +# You can have Apartment route to the appropriate Tenant by adding some Rack middleware. +# Apartment can support many different "Elevators" that can take care of this routing to your data. +# Require whichever Elevator you're using below or none if you have a custom one. +# +# require 'apartment/elevators/generic' +# require 'apartment/elevators/domain' +require 'apartment/elevators/subdomain' +# require 'apartment/elevators/first_subdomain' + +# +# Apartment Configuration +# +Apartment.configure do |config| + + # Add any models that you do not want to be multi-tenanted, but remain in the global (public) namespace. + # A typical example would be a Customer or Tenant model that stores each Tenant's information. + # + config.excluded_models = [ "User", "Company" ] + + # In order to migrate all of your Tenants you need to provide a list of Tenant names to Apartment. + # You can make this dynamic by providing a Proc object to be called on migrations. + # This object should yield either: + # - an array of strings representing each Tenant name. + # - a hash which keys are tenant names, and values custom db config (must contain all key/values required in database.yml) + # + # config.tenant_names = lambda{ Customer.pluck(:tenant_name) } + # config.tenant_names = ['tenant1', 'tenant2'] + # config.tenant_names = { + # 'tenant1' => { + # adapter: 'postgresql', + # host: 'some_server', + # port: 5555, + # database: 'postgres' # this is not the name of the tenant's db + # # but the name of the database to connect to before creating the tenant's db + # # mandatory in postgresql + # }, + # 'tenant2' => { + # adapter: 'postgresql', + # database: 'postgres' # this is not the name of the tenant's db + # # but the name of the database to connect to before creating the tenant's db + # # mandatory in postgresql + # } + # } + # config.tenant_names = lambda do + # Tenant.all.each_with_object({}) do |tenant, hash| + # hash[tenant.name] = tenant.db_configuration + # end + # end + # + + + # ==> PostgreSQL only options + + # Specifies whether to use PostgreSQL schemas or create a new database per Tenant. + # The default behaviour is true. + # + config.use_schemas = false + + # Apartment can be forced to use raw SQL dumps instead of schema.rb for creating new schemas. + # Use this when you are using some extra features in PostgreSQL that can't be respresented in + # schema.rb, like materialized views etc. (only applies with use_schemas set to true). + # (Note: this option doesn't use db/structure.sql, it creates SQL dump by executing pg_dump) + # + # config.use_sql = false + + # There are cases where you might want some schemas to always be in your search_path + # e.g when using a PostgreSQL extension like hstore. + # Any schemas added here will be available along with your selected Tenant. + # + # config.persistent_schemas = %w{ hstore } + + # <== PostgreSQL only options + # + + # By default, and only when not using PostgreSQL schemas, Apartment will prepend the environment + # to the tenant name to ensure there is no conflict between your environments. + # This is mainly for the benefit of your development and test environments. + # Uncomment the line below if you want to disable this behaviour in production. + # + config.prepend_environment = !Rails.env.production? +end + +# Setup a custom Tenant switching middleware. The Proc should return the name of the Tenant that +# you want to switch to. +# Rails.application.config.middleware.use 'Apartment::Elevators::Generic', lambda { |request| +# request.host.split('.').first +# } + +# Rails.application.config.middleware.use 'Apartment::Elevators::Domain' +Rails.application.config.middleware.use 'Apartment::Elevators::Subdomain' +# Rails.application.config.middleware.use 'Apartment::Elevators::FirstSubdomain' diff --git a/migrations/createDummyData.rb b/migrations/createDummyData.rb new file mode 100644 index 0000000..b932fba --- /dev/null +++ b/migrations/createDummyData.rb @@ -0,0 +1,35 @@ +require 'mysql2' +require 'active_record' + +ActiveRecord::Base.establish_connection( + adapter: 'mysql2', + host: 'localhost', + database: 'development_HoopersIsland', + username: 'bmv', + password: '1156244terps!' +) + +class Grade < ActiveRecord::Base + +end + +class Oyster < ActiveRecord::Base + +end + +class Run < ActiveRecord::Base + +end + +runs = Run.all +grades = Grade.all.to_a +runs.each do |run| + 20.times do + len = rand(0..10) + width = rand(0..10) + height = rand(0..10) + vol = len * width * height + oyster = Oyster.new(run_id: run.id, grade: grades[rand(0...grades.length)].Full_name,volume:vol, length:len, width:width, height:height) + oyster.save + end +end diff --git a/migrations/grade.rb b/migrations/grade.rb new file mode 100644 index 0000000..60fb844 --- /dev/null +++ b/migrations/grade.rb @@ -0,0 +1,24 @@ + +#A class to represent a grade +class Grade + + def initialize(params) + @id = params["grade_id"] + @full_name = params["Full_Name"] || "NULL" + @short_name = params["Short_Name"] || "NULL" + @volume_max = params["Volume_max"] || 0 + @volume_min = params["Volume_min"] || 0 + @length_max = params["Length_max"] || 0 + @length_min = params["Length_min"] || 0 + @width_max = params["Width_max"] || 0 + @width_min = params["Width_min"] || 0 + @height_max = params["Height_max"] || 0 + @height_min = params["Height_min"] || 0 + end + + def to_insert_query + "INSERT into grades (id, Full_Name, Short_Name, Volume_max, Volume_min, Length_max, Length_min, Width_max, Width_min, Height_max, Height_min,created_at,updated_at) VALUES + (#{@id},\"#{@full_name}\",\"#{@short_name}\",#{@volume_max},#{@volume_min},#{@length_max},#{@length_min},#{@width_max},#{@width_min},#{@height_max},#{@height_min},NOW(),NOW());" + end + +end diff --git a/migrate.rb b/migrations/migrate.rb similarity index 100% rename from migrate.rb rename to migrations/migrate.rb diff --git a/setup.rb b/setup.rb new file mode 100644 index 0000000..436c012 --- /dev/null +++ b/setup.rb @@ -0,0 +1,144 @@ +#Link every result to run id 48 +require 'mysql2' +require 'fileutils' + +$company_data_endpoint = "companydata.c02zesysnssi.us-west-2.rds.amazonaws.com" + +#A class to represent a run +class Run + + def initialize(params) + @run_id = params["run_id"] + @runDate = params["runDate"].strftime('%Y-%m-%d %H:%M:%S') || nil + @location = params["location"] || "NULL" + @supplier = params["supplier"] || "NULL" + @other = params["other"] || "NULL" + @machine_id = params["machine_id"] || "NULL" + @harvest_time = params["harvest time"] || "NULL" + @distributor = params["distributor"] || "NULL" + end + + def to_insert_query + "INSERT into runs (id, runDate, location, harvest_time, supplier, distributor, other, machine_id,created_at,updated_at) VALUES + (#{@run_id}, '#{@runDate}',\"#{@location}\",NOW(),\"#{@supplier}\",\"#{@distributor}\", + \"#{@other}\",#{@machine_id},NOW(),NOW());" + end + +end + +#A class to represent a grade +class Grade + + def initialize(params) + @id = params["grade_id"] + @full_name = params["Full_Name"] || "NULL" + @short_name = params["Short_Name"] || "NULL" + @volume_max = params["Volume_max"] || 0 + @volume_min = params["Volume_min"] || 0 + @length_max = params["Length_max"] || 0 + @length_min = params["Length_min"] || 0 + @width_max = params["Width_max"] || 0 + @width_min = params["Width_min"] || 0 + @height_max = params["Height_max"] || 0 + @height_min = params["Height_min"] || 0 + end + + def to_insert_query + "INSERT into grades (id, Full_Name, Short_Name, Volume_max, Volume_min, Length_max, Length_min, Width_max, Width_min, Height_max, Height_min,created_at,updated_at) VALUES + (#{@id},\"#{@full_name}\",\"#{@short_name}\",#{@volume_max},#{@volume_min},#{@length_max},#{@length_min},#{@width_max},#{@width_min},#{@height_max},#{@height_min},NOW(),NOW());" + end + +end + + +#This will run the initial migration that sets up the db to be apartment friendly +def initial_migration + apartment_copy_path = 'init/apartment.rb' + apartment_path = 'Pearlception/config/initializers/apartment.rb' + FileUtils.cp(apartment_path, 'init/apartment_copy' ) #Copy the original file back + FileUtils.rm(apartment_path) #Remove the original file + FileUtils.cp(apartment_copy_path,apartment_path) #Copy the blank copy into init + Dir.chdir('Pearlception') do + puts `rake db:setup` + puts `rake db:migrate` #Run the migration + end + FileUtils.rm(apartment_path) #Remove the blank copy + FileUtils.cp('init/apartment_copy',apartment_path) + FileUtils.rm('init/apartment_copy') +end + +#Runs the initial bundle install +def bundle + Dir.chdir("Pearlception") do + puts `bundle install` + end +end + +#This will insert the initial IVA admin needed to run the website. +def setup_initial_admin + client = Mysql2::Client.new(host:'localhost' ,username:"bmv", password:"1156244terps!", database: "Pearlception_development") + client.query("INSERT INTO companies (company_name, company_token, created_at, updated_at) VALUES (\"IVA\", \"a41b23cf-1d61-4fb4-9b69-0167abd7c583\",NOW(),NOW())") +end + +#This will migrate over all the runs that are on the AWS database to your local db +def migrate_runs + client = Mysql2::Client.new(host: $company_data_endpoint, username: 'ivauser', password: 'ivapassword', database: 'Hooper\'s Island') + local_client = Mysql2::Client.new(host:'localhost' ,username:"bmv", password:"1156244terps!", database: "development_HoopersIsland") + client.query("SELECT * FROM runs").each do |params| + run = Run.new(params) + puts run.to_insert_query + local_client.query(run.to_insert_query) + end +end + + +#This will migrate over all the oystersd +def migrate_grades + client = Mysql2::Client.new(host: $company_data_endpoint, username: 'ivauser', password: 'ivapassword', database: 'Hooper\'s Island') + local_client = Mysql2::Client.new(host:'localhost' ,username:"bmv", password:"1156244terps!", database: "development_HoopersIsland") + client.query("SELECT * FROM grades").each do |params| + grade = Grade.new(params) + local_client.query(grade.to_insert_query) + end +end + +#This will remvoe hoopers island DB +def drop_hoopers + client = Mysql2::Client.new(host:'localhost' ,username:"bmv", password:"1156244terps!", database: "Pearlception_development") + client.query("DROP DATABASE development_HoopersIsland;") +end + + +#This will setup the Hooper's Island DB +def setup_hoopers + client = Mysql2::Client.new(host:'localhost' ,username:"bmv", password:"1156244terps!", database: "Pearlception_development") + client.query("CREATE DATABASE development_HoopersIsland;") + client.query("INSERT INTO companies (company_name, company_token, created_at, updated_at) VALUES (\"Hooper's Island\",\"c25f10d9-61ad-4d2e-85fe-21f770d9a391\",NOW(),NOW());") +end + + +########## MAIN METHOD ##################### +if ARGV.include?("init") #What you should run upon a fresh clone eg: ruby setup.rb init + bundle + initial_migration + setup_initial_admin +end + +if ARGV.include? "reset" #What to run if you want to reset ALL the data in the DBs eg: ruby setup.rb reset + Dir.chdir("Pearlception") do + puts `rake db:drop` + end + initial_migration + drop_hoopers + setup_initial_admin +end + +if ARGV.include? "hoopers" + begin + setup_hoopers + rescue + puts "Hoopers already exists" + end + migrate_runs +end +migrate_grades