Commit 8148bfa7 authored by Hugo's avatar Hugo
Browse files

Major revision phase 2: code cleanup, adding layer for processed counts

parent 3e2c4f49
AllCops:
TargetRubyVersion: 2.4
Metrics/LineLength:
# This will disable the rule completely, regardless what other options you put
#Enabled: false
......
source "http://rubygems.org"
gem 'mysql2', '~> 0.5'
gem 'net-http-digest_auth'
gem 'activerecord'
gem "sinatra", "~> 2"
gem "sinatra-contrib", "~> 2"
gem 'thin'
gem 'pry'
gem 'rake'
gem 'rspec'
gem 'sqlite3'
gem 'bullet', '~> 5.9', require: true
\ No newline at end of file
gem 'mysql2', '~> 0.5.2'
gem 'net-http-digest_auth', '~> 1.4', '>= 1.4.1'
gem 'activerecord', '~> 5.2', '>= 5.2.2.1'
gem 'sinatra', '~> 2.0', '>= 2.0.5'
gem 'sinatra-contrib', '~> 2.0', '>= 2.0.5'
gem 'thin', '~> 1.7', '>= 1.7.2'
gem 'pry', '~> 0.12.2'
gem 'rake', '~> 12.3', '>= 12.3.2'
gem 'rspec', '~> 3.8'
gem 'sqlite3', '~> 1.3', '>= 1.3.13', '< 1.4'
gem 'bullet', '~> 5.9'
gem 'rdiscount', '~> 2.2', '>= 2.2.0.1'
gem 'rubocop', '~> 0.42.0'
\ No newline at end of file
GEM
remote: http://rubygems.org/
specs:
activemodel (5.2.2)
activesupport (= 5.2.2)
activerecord (5.2.2)
activemodel (= 5.2.2)
activesupport (= 5.2.2)
activemodel (5.2.2.1)
activesupport (= 5.2.2.1)
activerecord (5.2.2.1)
activemodel (= 5.2.2.1)
activesupport (= 5.2.2.1)
arel (>= 9.0)
activesupport (5.2.2)
activesupport (5.2.2.1)
concurrent-ruby (~> 1.0, >= 1.0.2)
i18n (>= 0.7, < 2)
minitest (~> 5.1)
tzinfo (~> 1.1)
arel (9.0.0)
backports (3.11.4)
ast (2.4.0)
backports (3.12.0)
bullet (5.9.0)
activesupport (>= 3.0.0)
uniform_notifier (~> 1.11)
coderay (1.1.2)
concurrent-ruby (1.1.4)
concurrent-ruby (1.1.5)
daemons (1.3.1)
diff-lcs (1.3)
eventmachine (1.2.7)
i18n (1.5.3)
i18n (1.6.0)
concurrent-ruby (~> 1.0)
method_source (0.9.2)
minitest (5.11.3)
......@@ -30,13 +31,19 @@ GEM
mustermann (1.0.3)
mysql2 (0.5.2)
net-http-digest_auth (1.4.1)
parser (2.6.2.0)
ast (~> 2.4.0)
powerpack (0.1.2)
pry (0.12.2)
coderay (~> 1.1.0)
method_source (~> 0.9.0)
rack (2.0.6)
rack-protection (2.0.5)
rack
rainbow (2.2.2)
rake
rake (12.3.2)
rdiscount (2.2.0.1)
rspec (3.8.0)
rspec-core (~> 3.8.0)
rspec-expectations (~> 3.8.0)
......@@ -50,6 +57,13 @@ GEM
diff-lcs (>= 1.2.0, < 2.0)
rspec-support (~> 3.8.0)
rspec-support (3.8.0)
rubocop (0.42.0)
parser (>= 2.3.1.1, < 3.0)
powerpack (~> 0.1)
rainbow (>= 1.99.1, < 3.0)
ruby-progressbar (~> 1.7)
unicode-display_width (~> 1.0, >= 1.0.1)
ruby-progressbar (1.10.0)
sinatra (2.0.5)
mustermann (~> 1.0)
rack (~> 2.0)
......@@ -71,23 +85,26 @@ GEM
tilt (2.0.9)
tzinfo (1.2.5)
thread_safe (~> 0.1)
unicode-display_width (1.5.0)
uniform_notifier (1.12.1)
PLATFORMS
ruby
DEPENDENCIES
activerecord
activerecord (~> 5.2, >= 5.2.2.1)
bullet (~> 5.9)
mysql2 (~> 0.5)
net-http-digest_auth
pry
rake
rspec
sinatra (~> 2)
sinatra-contrib (~> 2)
sqlite3
thin
mysql2 (~> 0.5.2)
net-http-digest_auth (~> 1.4, >= 1.4.1)
pry (~> 0.12.2)
rake (~> 12.3, >= 12.3.2)
rdiscount (~> 2.2, >= 2.2.0.1)
rspec (~> 3.8)
rubocop (~> 0.42.0)
sinatra (~> 2.0, >= 2.0.5)
sinatra-contrib (~> 2.0, >= 2.0.5)
sqlite3 (~> 1.3, >= 1.3.13, < 1.4)
thin (~> 1.7, >= 1.7.2)
BUNDLED WITH
2.0.1
......@@ -2,11 +2,11 @@
Application for harvesting and presenting visitor statistics. Consists of a script that collects traffic data from off-site cameras and saves them to a local database, and a website for analyzing said data.
### Installation
#### Ruby
If not installed already, do `sudo apt-get install libmysqlclient-dev`. Next get rvm with: `gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3` followed by `curl -sSL https://get.rvm.io | bash -s stable`. Close and reopen the terminal, then invoke `source ~/.rvm/scripts/rvm` and `rvm install 2.3` (user needs to be in sudoers list for this step). Grab bundler with `gem install bundler`, change to the app directory and do `bundle install`.
If not installed already, do `sudo apt-get install libmysqlclient-dev`. Next get rvm with: `gpg --keyserver hkp://keys.gnupg.net --recv-keys 409B6B1796C275462A1703113804BB82D39DC0E3` followed by `curl -sSL https://get.rvm.io | bash -s stable`. Close and reopen the terminal, then invoke `source ~/.rvm/scripts/rvm` and `rvm install 2.6.0` (user needs to be in sudoers list for this step). Grab bundler with `gem install bundler`, change to the app directory and do `bundle install`.
#### MySQL
......@@ -17,7 +17,6 @@ Next, set up the user for the web server:
`CREATE USER 'camweb'@'localhost' IDENTIFIED BY 'secret';`
`GRANT ALL PRIVILEGES on counterstat.* to 'camweb'@'localhost'`
#### Static Page (currently optional)
Set the directory for the static page in the settings file. The directory should also have a copy of the assets folder.
......@@ -26,29 +25,26 @@ Set the directory for the static page in the settings file. The directory should
There are many ways to set up the webserver, for example as a standalone Thin server or as a Phusion Passenger. For local testing, `ruby counterweb.rb` should start it on port 4567.
#### Cron
For hourly updates, set up /etc/cron.d/counterstat as follows:
```sh
0 * * * * camstat /bin/bash -l -c 'source /home/camstat/.rvm/environments/ruby-2.3.0 && cd /usr/local/src/counterstat && ruby counterstat.rb --days=28 ; /home/camstat/bin/push-web.sh >> cron.log 2>&1'
0 * * * * camstat /bin/bash -l -c 'source /home/camstat/.rvm/environments/ruby-2.6.0 && cd /usr/local/src/counterstat && ruby counterstat.rb ; /home/camstat/bin/push-web.sh >> cron.log 2>&1'
10 01 * * * camstat /bin/bash -l -c 'source /home/camstat/.rvm/environments/ruby-2.3.0 && cd /usr/local/src/counterstat && ruby counterstat.rb --niterun --days=28 ; /home/camstat/bin/push-web.sh >> cron.log 2>&1'
10 01 * * * camstat /bin/bash -l -c 'source /home/camstat/.rvm/environments/ruby-2.6.0 && cd /usr/local/src/counterstat && ruby counterstat.rb --niterun ; /home/camstat/bin/push-web.sh >> cron.log 2>&1'
```
The --niterun job handles pending schedules and ensures all records from previous day is collected, and must not be omitted.
### Program switches
### Program switches:
+ **--days=n** Specifies the number of days to be covered in the html report
+ **--date=yyyy-mm-dd** The script is designed to be run hourly, and will hence collect today's stats by default. This switch overrides this behavior.
+ **--niterun** Is run once after midnight to ensure all entries for the previous day is collected. Also handles pending schedules. Does not combine with --date.
+ **-r** Primarily for development. Refreshes the report without accessing the cameras.
### Maintenance
A few simple utility scripts reside in the maintenance folder:
`recode.rb` updates the "Meråpent" codes based on the opening hours scheme in the database. Usage: `ruby recode.rb [branch name] [start date] [end date]`
......@@ -57,8 +53,8 @@ A few simple utility scripts reside in the maintenance folder:
`reload.rb` downloads data from the camera(s) to the database. Can be used to fix incomplete data sets found with `check_integrity`. Note that the cameras only hold their data for 90 days, and that reloaded data will be coded according to the currently active opening schedule. Usage: `ruby reload.rb [branch name] [start date] [end date]`
### Design and implementation
The basic design can be crudely drawn as follows:
![beautiful software](docs/design1.png "Image 1")
......@@ -68,18 +64,21 @@ In order to speed up the web presentation, all branches and counters also have m
The database is described in schema.rb (ActiveRecord snapshot).
#### Data harvesting
Data is collected hourly by a script that connects to each camera and feeds the results into a local MySQL database. Every time a count is updated, a dirty bit is set for the materialized views associated with the timestamp. Once the script has finished downloading from all the cameras, the dirty bits are cleaned - leaving the views fully updated.
A more thorough version of the script is run after midnight, doing various integrity checks and fixes and activating any pending schedules.
#### Data presentation
Materialized views currently exist for Daily, Weekly and Monthly Statistics. These can be inspected via three different views:
* A branch mode to view visitor traffic for each individual branch.
* A report mode tailored to the administration's reporting needs.
* A subcounter mode to quickly analyze ingoing/outgoing ratios for each counter.
+ A branch mode to view visitor traffic for each individual branch.
+ A report mode tailored to the administration's reporting needs.
+ A subcounter mode to quickly analyze ingoing/outgoing ratios for each counter.
In addition, column visibility can be adjusted via the radio buttons above the table. Various graphs are also available where they're thought to be useful.
#### Admin interface
A simple interface for maintaining opening schedules and counter information is included.
require "active_record"
require "pry"
require_relative "./counterstat"
require_relative "./settings"
require 'rubygems'
#require 'bundler/setup'
require_relative 'models/countermodels'
ActiveRecord::Base.establish_connection(Settings::DB)
task :irb do
require 'irb'
......@@ -12,13 +12,50 @@ task :irb do
IRB.start
end
task :console do
ActiveRecord::Base.establish_connection(Settings::DB)
binding.pry
end
task :update_datetime do
Count.where(datetime: '2000-01-01 00:00:00').each do |count|
date = count.date
time = count.time
datetime = Time.new(date.year, date.month, date.day, time.hour, time.min, 0, 0) - 15.minutes
count.update_attribute(:datetime, datetime)
end
end
namespace :maintenance do
desc "Reprocess all counts. Warning: takes a lot of time"
task :reprocess do
Counter.all.each do |counter|
puts "Processing #{counter.name}"
counter.process_all_counts
end
puts "Reprocessing done"
end
desc "Reindex database. Warning: takes a lot of time"
task :rebuild_stats do
StatisticsView.rebuild
puts "All done"
end
desc "Repair index. Warning: takes a lot of time"
task :repair_stats do
StatisticsView.repair
puts "All done"
end
desc "Updates views by cleaning dirty bits. May take a lot of time"
task :update_view do
puts "Update started"
StatisticsView.clean_dirty_bits
puts "StatisticsViews updated"
end
end
namespace :db do
desc "Create the database"
......
# encoding: utf-8
require 'rubygems'
require 'bundler/setup'
require_relative 'settings'
require_relative 'models/countermodels'
require_relative 'datacollector'
require_relative 'reportmanager/reportmanager'
require_relative 'graphmanager/graphmanager'
ActiveRecord::Base.establish_connection(Settings::DB)
......
This diff is collapsed.
......@@ -23,7 +23,11 @@ class DataCollector
has_oh = branch.has_active_oh?
branch.counters.active.each do |counter|
collect_stats_for(branch, counter, date, has_oh)
begin
collect_stats_for(branch, counter, date, has_oh)
rescue => each
puts e.inspect
end
end
end
end
......
AccumulatedBranch.create("id"=>1, "name"=>"Samlet", "branch_code"=>"all")
Branch.create("id"=>1, "name"=>"Furuset", "branch_code"=>"ffur")
Branch.create("id"=>9, "name"=>"Røa", "branch_code"=>"froa")
Entrance.create("id"=>1, "branch_id"=>1, "name"=>"Hovedinngang", "first_active_date"=>"2016-03-04", "last_active_date"=>nil, "description"=>"")
Entrance.create("id"=>2, "branch_id"=>1, "name"=>"Meråpent", "first_active_date"=>"2016-03-04", "last_active_date"=>nil, "description"=>"")
Entrance.create("id"=>3, "branch_id"=>1, "name"=>"Annen etasje", "first_active_date"=>"2016-03-04", "last_active_date"=>nil, "description"=>"")
Entrance.create("id"=>4, "branch_id"=>1, "name"=>"fire", "first_active_date"=>"2016-10-31", "last_active_date"=>nil, "description"=>"")
Entrance.create("id"=>11, "branch_id"=>9, "name"=>"Hovedinngang", "first_active_date"=>"2017-01-01", "last_active_date"=>nil, "description"=>"")
Entrance.create("id"=>12, "branch_id"=>9, "name"=>"Sekundærinngang", "first_active_date"=>"2017-01-01", "last_active_date"=>nil, "description"=>"")
Counter.create("id"=>1, "branch_id"=>1, "source_id"=>1, "source_type"=>"Camera", "is_active"=>true, "source_type_id"=>1, "last_active_date"=>nil, "first_active_date"=>"2016-03-04", "entrance_id"=>1, "counter_interface_id"=>1)
Counter.create("id"=>2, "branch_id"=>1, "source_id"=>2, "source_type"=>"Camera", "is_active"=>true, "source_type_id"=>1, "last_active_date"=>nil, "first_active_date"=>"2016-03-04", "entrance_id"=>2, "counter_interface_id"=>1)
Counter.create("id"=>3, "branch_id"=>1, "source_id"=>3, "source_type"=>"Camera", "is_active"=>true, "source_type_id"=>1, "last_active_date"=>nil, "first_active_date"=>"2016-03-04", "entrance_id"=>3, "counter_interface_id"=>1)
Counter.create("id"=>7, "branch_id"=>1, "source_id"=>7, "source_type"=>"Camera", "is_active"=>true, "source_type_id"=>1, "last_active_date"=>nil, "first_active_date"=>"2016-10-31", "entrance_id"=>4, "counter_interface_id"=>1)
Counter.create("id"=>11, "branch_id"=>9, "source_id"=>11, "source_type"=>"Camera", "is_active"=>true, "source_type_id"=>1, "last_active_date"=>nil, "first_active_date"=>"2017-03-12", "entrance_id"=>11, "counter_interface_id"=>1)
Counter.create("id"=>30, "branch_id"=>9, "source_id"=>10, "source_type"=>"Portal", "is_active"=>false, "source_type_id"=>2, "last_active_date"=>"2017-03-12", "first_active_date"=>"2017-01-01", "entrance_id"=>11, "counter_interface_id"=>4)
Counter.create("id"=>31, "branch_id"=>9, "source_id"=>11, "source_type"=>"Portal", "is_active"=>false, "source_type_id"=>2, "last_active_date"=>"2017-09-30", "first_active_date"=>"2017-01-01", "entrance_id"=>12, "counter_interface_id"=>4)
Counter.create("id"=>43, "branch_id"=>9, "source_id"=>29, "source_type"=>"Camera", "is_active"=>true, "source_type_id"=>1, "last_active_date"=>nil, "first_active_date"=>"2018-01-22", "entrance_id"=>12, "counter_interface_id"=>1)
Camera.create("id"=>1, "branch_id"=>1, "name"=>"teller1-furu-inngang", "address"=>"http://teller1-furu.deich.folkebibl.no/", "user"=>"teller", "pw"=>"ento", "camera_interface_id"=>1)
Camera.create("id"=>2, "branch_id"=>1, "name"=>"teller2-furu-merapent", "address"=>"http://teller2-furu.deich.folkebibl.no/", "user"=>"teller", "pw"=>"ento", "camera_interface_id"=>1)
Camera.create("id"=>3, "branch_id"=>1, "name"=>"teller3-furu-andre", "address"=>"http://teller3-furu.deich.folkebibl.no/", "user"=>"teller", "pw"=>"ento", "camera_interface_id"=>1)
Camera.create("id"=>7, "branch_id"=>1, "name"=>"teller4-furu", "address"=>"http://teller4-furu.deich.folkebibl.no", "user"=>"teller", "pw"=>"ento", "camera_interface_id"=>1)
Camera.create("id"=>11, "branch_id"=>9, "name"=>"teller-1-roa", "address"=>"http://teller1-roa.deich.folkebibl.no", "user"=>"teller", "pw"=>"ento", "camera_interface_id"=>1)
Portal.create("id"=>10, "branch_id"=>9, "name"=>"roa1", "ip"=>"")
Portal.create("id"=>11, "branch_id"=>9, "name"=>"roa2", "ip"=>"")
Camera.create("id"=>29, "branch_id"=>9, "name"=>"teller-2-roa", "address"=>"http://teller2-roa.deich.folkebibl.no", "user"=>"teller", "pw"=>"ento", "camera_interface_id"=>1)
AccumulatedBranch.create(["id=>key.is_a?(Date) ? value.strftime : value", "name=>key.is_a?(Date) ? value.strftime : value", "branch_code=>key.is_a?(Date) ? value.strftime : value"])
Branch.create(["id=>key.is_a?(Date) ? value.strftime : value", "name=>key.is_a?(Date) ? value.strftime : value", "branch_code=>key.is_a?(Date) ? value.strftime : value"])
Branch.create(["id=>key.is_a?(Date) ? value.strftime : value", "name=>key.is_a?(Date) ? value.strftime : value", "branch_code=>key.is_a?(Date) ? value.strftime : value"])
Entrance.create(["id=>key.is_a?(Date) ? value.strftime : value", "branch_id=>key.is_a?(Date) ? value.strftime : value", "name=>key.is_a?(Date) ? value.strftime : value", "description=>key.is_a?(Date) ? value.strftime : value"])
Entrance.create(["id=>key.is_a?(Date) ? value.strftime : value", "branch_id=>key.is_a?(Date) ? value.strftime : value", "name=>key.is_a?(Date) ? value.strftime : value", "description=>key.is_a?(Date) ? value.strftime : value"])
Entrance.create(["id=>key.is_a?(Date) ? value.strftime : value", "branch_id=>key.is_a?(Date) ? value.strftime : value", "name=>key.is_a?(Date) ? value.strftime : value", "description=>key.is_a?(Date) ? value.strftime : value"])
Entrance.create(["id=>key.is_a?(Date) ? value.strftime : value", "branch_id=>key.is_a?(Date) ? value.strftime : value", "name=>key.is_a?(Date) ? value.strftime : value", "description=>key.is_a?(Date) ? value.strftime : value"])
Entrance.create(["id=>key.is_a?(Date) ? value.strftime : value", "branch_id=>key.is_a?(Date) ? value.strftime : value", "name=>key.is_a?(Date) ? value.strftime : value", "description=>key.is_a?(Date) ? value.strftime : value"])
Entrance.create(["id=>key.is_a?(Date) ? value.strftime : value", "branch_id=>key.is_a?(Date) ? value.strftime : value", "name=>key.is_a?(Date) ? value.strftime : value", "description=>key.is_a?(Date) ? value.strftime : value"])
Counter.create(["id=>key.is_a?(Date) ? value.strftime : value", "branch_id=>key.is_a?(Date) ? value.strftime : value", "source_id=>key.is_a?(Date) ? value.strftime : value", "source_type=>key.is_a?(Date) ? value.strftime : value", "is_active=>key.is_a?(Date) ? value.strftime : value", "source_type_id=>key.is_a?(Date) ? value.strftime : value", "last_active_date=>key.is_a?(Date) ? value.strftime : value", "first_active_date=>key.is_a?(Date) ? value.strftime : value", "entrance_id=>key.is_a?(Date) ? value.strftime : value", "counter_interface_id=>key.is_a?(Date) ? value.strftime : value"])
Counter.create(["id=>key.is_a?(Date) ? value.strftime : value", "branch_id=>key.is_a?(Date) ? value.strftime : value", "source_id=>key.is_a?(Date) ? value.strftime : value", "source_type=>key.is_a?(Date) ? value.strftime : value", "is_active=>key.is_a?(Date) ? value.strftime : value", "source_type_id=>key.is_a?(Date) ? value.strftime : value", "last_active_date=>key.is_a?(Date) ? value.strftime : value", "first_active_date=>key.is_a?(Date) ? value.strftime : value", "entrance_id=>key.is_a?(Date) ? value.strftime : value", "counter_interface_id=>key.is_a?(Date) ? value.strftime : value"])
Counter.create(["id=>key.is_a?(Date) ? value.strftime : value", "branch_id=>key.is_a?(Date) ? value.strftime : value", "source_id=>key.is_a?(Date) ? value.strftime : value", "source_type=>key.is_a?(Date) ? value.strftime : value", "is_active=>key.is_a?(Date) ? value.strftime : value", "source_type_id=>key.is_a?(Date) ? value.strftime : value", "last_active_date=>key.is_a?(Date) ? value.strftime : value", "first_active_date=>key.is_a?(Date) ? value.strftime : value", "entrance_id=>key.is_a?(Date) ? value.strftime : value", "counter_interface_id=>key.is_a?(Date) ? value.strftime : value"])
Counter.create(["id=>key.is_a?(Date) ? value.strftime : value", "branch_id=>key.is_a?(Date) ? value.strftime : value", "source_id=>key.is_a?(Date) ? value.strftime : value", "source_type=>key.is_a?(Date) ? value.strftime : value", "is_active=>key.is_a?(Date) ? value.strftime : value", "source_type_id=>key.is_a?(Date) ? value.strftime : value", "last_active_date=>key.is_a?(Date) ? value.strftime : value", "first_active_date=>key.is_a?(Date) ? value.strftime : value", "entrance_id=>key.is_a?(Date) ? value.strftime : value", "counter_interface_id=>key.is_a?(Date) ? value.strftime : value"])
Counter.create(["id=>key.is_a?(Date) ? value.strftime : value", "branch_id=>key.is_a?(Date) ? value.strftime : value", "source_id=>key.is_a?(Date) ? value.strftime : value", "source_type=>key.is_a?(Date) ? value.strftime : value", "is_active=>key.is_a?(Date) ? value.strftime : value", "source_type_id=>key.is_a?(Date) ? value.strftime : value", "last_active_date=>key.is_a?(Date) ? value.strftime : value", "first_active_date=>key.is_a?(Date) ? value.strftime : value", "entrance_id=>key.is_a?(Date) ? value.strftime : value", "counter_interface_id=>key.is_a?(Date) ? value.strftime : value"])
Counter.create(["id=>key.is_a?(Date) ? value.strftime : value", "branch_id=>key.is_a?(Date) ? value.strftime : value", "source_id=>key.is_a?(Date) ? value.strftime : value", "source_type=>key.is_a?(Date) ? value.strftime : value", "is_active=>key.is_a?(Date) ? value.strftime : value", "source_type_id=>key.is_a?(Date) ? value.strftime : value", "last_active_date=>key.is_a?(Date) ? value.strftime : value", "first_active_date=>key.is_a?(Date) ? value.strftime : value", "entrance_id=>key.is_a?(Date) ? value.strftime : value", "counter_interface_id=>key.is_a?(Date) ? value.strftime : value"])
Counter.create(["id=>key.is_a?(Date) ? value.strftime : value", "branch_id=>key.is_a?(Date) ? value.strftime : value", "source_id=>key.is_a?(Date) ? value.strftime : value", "source_type=>key.is_a?(Date) ? value.strftime : value", "is_active=>key.is_a?(Date) ? value.strftime : value", "source_type_id=>key.is_a?(Date) ? value.strftime : value", "last_active_date=>key.is_a?(Date) ? value.strftime : value", "first_active_date=>key.is_a?(Date) ? value.strftime : value", "entrance_id=>key.is_a?(Date) ? value.strftime : value", "counter_interface_id=>key.is_a?(Date) ? value.strftime : value"])
Counter.create(["id=>key.is_a?(Date) ? value.strftime : value", "branch_id=>key.is_a?(Date) ? value.strftime : value", "source_id=>key.is_a?(Date) ? value.strftime : value", "source_type=>key.is_a?(Date) ? value.strftime : value", "is_active=>key.is_a?(Date) ? value.strftime : value", "source_type_id=>key.is_a?(Date) ? value.strftime : value", "last_active_date=>key.is_a?(Date) ? value.strftime : value", "first_active_date=>key.is_a?(Date) ? value.strftime : value", "entrance_id=>key.is_a?(Date) ? value.strftime : value", "counter_interface_id=>key.is_a?(Date) ? value.strftime : value"])
Camera.create(["id=>key.is_a?(Date) ? value.strftime : value", "branch_id=>key.is_a?(Date) ? value.strftime : value", "name=>key.is_a?(Date) ? value.strftime : value", "address=>key.is_a?(Date) ? value.strftime : value", "user=>key.is_a?(Date) ? value.strftime : value", "pw=>key.is_a?(Date) ? value.strftime : value", "camera_interface_id=>key.is_a?(Date) ? value.strftime : value"])
Camera.create(["id=>key.is_a?(Date) ? value.strftime : value", "branch_id=>key.is_a?(Date) ? value.strftime : value", "name=>key.is_a?(Date) ? value.strftime : value", "address=>key.is_a?(Date) ? value.strftime : value", "user=>key.is_a?(Date) ? value.strftime : value", "pw=>key.is_a?(Date) ? value.strftime : value", "camera_interface_id=>key.is_a?(Date) ? value.strftime : value"])
Camera.create(["id=>key.is_a?(Date) ? value.strftime : value", "branch_id=>key.is_a?(Date) ? value.strftime : value", "name=>key.is_a?(Date) ? value.strftime : value", "address=>key.is_a?(Date) ? value.strftime : value", "user=>key.is_a?(Date) ? value.strftime : value", "pw=>key.is_a?(Date) ? value.strftime : value", "camera_interface_id=>key.is_a?(Date) ? value.strftime : value"])
Camera.create(["id=>key.is_a?(Date) ? value.strftime : value", "branch_id=>key.is_a?(Date) ? value.strftime : value", "name=>key.is_a?(Date) ? value.strftime : value", "address=>key.is_a?(Date) ? value.strftime : value", "user=>key.is_a?(Date) ? value.strftime : value", "pw=>key.is_a?(Date) ? value.strftime : value", "camera_interface_id=>key.is_a?(Date) ? value.strftime : value"])
Portal.create(["id=>key.is_a?(Date) ? value.strftime : value", "branch_id=>key.is_a?(Date) ? value.strftime : value", "name=>key.is_a?(Date) ? value.strftime : value", "ip=>key.is_a?(Date) ? value.strftime : value"])
Portal.create(["id=>key.is_a?(Date) ? value.strftime : value", "branch_id=>key.is_a?(Date) ? value.strftime : value", "name=>key.is_a?(Date) ? value.strftime : value", "ip=>key.is_a?(Date) ? value.strftime : value"])
Camera.create(["id=>key.is_a?(Date) ? value.strftime : value", "branch_id=>key.is_a?(Date) ? value.strftime : value", "name=>key.is_a?(Date) ? value.strftime : value", "address=>key.is_a?(Date) ? value.strftime : value", "user=>key.is_a?(Date) ? value.strftime : value", "pw=>key.is_a?(Date) ? value.strftime : value", "camera_interface_id=>key.is_a?(Date) ? value.strftime : value"])
Camera.create(["id=>key.is_a?(Date) ? value.strftime : value", "branch_id=>key.is_a?(Date) ? value.strftime : value", "name=>key.is_a?(Date) ? value.strftime : value", "address=>key.is_a?(Date) ? value.strftime : value", "user=>key.is_a?(Date) ? value.strftime : value", "pw=>key.is_a?(Date) ? value.strftime : value", "camera_interface_id=>key.is_a?(Date) ? value.strftime : value"])
......@@ -18,6 +18,9 @@ def dump(items)
end
end
interfaces = CounterInterface.all
dump(interfaces)
accumulatedBranch = AccumulatedBranch.all
dump(accumulatedBranch)
......@@ -36,6 +39,6 @@ dump(cameras)
primary_periods = counters.map {|counter| counter.primary_source_periods}.flatten
dump(primary_periods)
#ct = counters[0].counts.limit(5)
#dump(ct)
ct = counters[0].counts.limit(5)
dump(ct)
OpeningHours.create(:branch_id => 11, :weekday_id => 1, :morning_start => '07:00', :morning_stop => '10:00', :regular_start => '10:00', :regular_stop => '18:00', :night_start => '18:00', :night_stop => '23:00')
OpeningHours.create(:branch_id => 11, :weekday_id => 2, :morning_start => '07:00', :morning_stop => '10:00', :regular_start => '10:00', :regular_stop => '18:00', :night_start => '18:00', :night_stop => '23:00')
OpeningHours.create(:branch_id => 11, :weekday_id => 3, :morning_start => '07:00', :morning_stop => '10:00', :regular_start => '10:00', :regular_stop => '18:00', :night_start => '18:00', :night_stop => '23:00')
OpeningHours.create(:branch_id => 11, :weekday_id => 4, :morning_start => '07:00', :morning_stop => '10:00', :regular_start => '10:00', :regular_stop => '18:00', :night_start => '18:00', :night_stop => '23:00')
OpeningHours.create(:branch_id => 11, :weekday_id => 5, :morning_start => '07:00', :morning_stop => '10:00', :regular_start => '10:00', :regular_stop => '16:00', :night_start => '16:00', :night_stop => '23:00')
OpeningHours.create(:branch_id => 11, :weekday_id => 6, :morning_start => '07:00', :morning_stop => '12:00', :regular_start => '12:00', :regular_stop => '16:00', :night_start => '16:00', :night_stop => '23:00')
OpeningHours.create(:branch_id => 11, :weekday_id => 7, :morning_start => '07:00', :morning_stop => '23:00')
......@@ -15,6 +15,7 @@ ActiveRecord::Schema.define(version: 0) do
create_table "accumulated_branches", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
t.string "name", limit: 30, null: false
t.string "branch_code"
t.date "first_active_date"
t.index ["branch_code"], name: "branch_code", unique: true
t.index ["name"], name: "name", unique: true
end
......@@ -31,11 +32,6 @@ ActiveRecord::Schema.define(version: 0) do
t.index ["branch_code"], name: "branch_code", unique: true
end
create_table "camera_interfaces", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
t.string "name", null: false
t.string "description", limit: 1024
end
create_table "cameras", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
t.string "name", limit: 40, null: false
t.string "address", limit: 100, null: false
......@@ -77,14 +73,11 @@ ActiveRecord::Schema.define(version: 0) do
create_table "counts", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
t.integer "counter_id", null: false
t.date "date", null: false
t.time "time", null: false
t.integer "visitors_in", limit: 2, default: 0, unsigned: true
t.integer "visitors_out", limit: 2, default: 0, unsigned: true
t.string "oh_code", limit: 1
t.boolean "is_primary_source", default: true
t.index ["counter_id", "date", "time"], name: "counter_id", unique: true
t.index ["date"], name: "idx_date"
t.datetime "datetime", default: "2000-01-01 00:00:00", null: false
end
create_table "downtimes", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
......@@ -114,18 +107,6 @@ ActiveRecord::Schema.define(version: 0) do
t.integer "active_schedule_id", null: false
end
create_table "overlapping_counters", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
t.integer "overlap_id", null: false
t.integer "counter_id", null: false
t.string "description"
t.index ["overlap_id", "counter_id"], name: "id_overlap_counter", unique: true
end
create_table "overlaps", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
t.string "name", null: false
t.string "description"
end
create_table "pending_hours", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
t.integer "weekday_id", limit: 2, null: false, unsigned: true
t.time "morning_start"
......@@ -159,9 +140,17 @@ ActiveRecord::Schema.define(version: 0) do
t.index ["entrance_id"], name: "fk_psp_entrance"
end
create_table "source_types", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
t.string "name", limit: 30, null: false
t.string "description"
create_table "processed_counts", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
t.integer "counter_id", null: false
t.datetime "datetime"
t.integer "visitors_in_raw", default: 0, null: false
t.integer "visitors_out_raw", default: 0, null: false
t.integer "visitors_in", default: 0, null: false
t.integer "visitors_out", default: 0, null: false
t.boolean "is_primary_source", null: false
t.string "oh_code", limit: 1
t.integer "count_correction_id"
t.index ["counter_id", "datetime"], name: "uk_counter_id_datetime", unique: true
end
create_table "statistics_views", id: :integer, options: "ENGINE=InnoDB DEFAULT CHARSET=latin1", force: :cascade do |t|
......@@ -189,6 +178,9 @@ ActiveRecord::Schema.define(version: 0) do
t.integer "extended_total", default: 0, null: false
t.boolean "dirty_bit", default: true
t.boolean "is_missing_record"
t.integer "visitors_in_raw", default: 0, null: false
t.integer "visitors_out_raw", default: 0, null: false
t.integer "visitors_total_raw", default: 0, null: false
t.index ["date"], name: "date"
t.index ["type", "aggregate_id", "aggregate_type", "date"], name: "unique_index", unique: true
end
......@@ -207,4 +199,5 @@ ActiveRecord::Schema.define(version: 0) do
add_foreign_key "entrances", "branches", name: "entrances_ibfk_1"
add_foreign_key "primary_source_periods", "counters", name: "primary_source_periods_ibfk_1"
add_foreign_key "primary_source_periods", "entrances", name: "primary_source_periods_ibfk_2"
add_foreign_key "processed_counts", "counters", name: "processed_counts_ibfk_1"
end
# encoding: utf-8
require 'active_record'
require_relative './countermodels'
require_relative "./settings"
ActiveRecord::Base.establish_connection(Settings::DB)
begin
new_branch = Branch.create(:branch_id => 11, :name => 'Furuset')
new_camera = Camera.create(:branch_id => new_branch.branch_id, :name => "teller1-furu-inngang", :address => "http://teller1-furu.deich.folkebibl.no/", :user => "secret", :pw => "secret")
Counter.create(:branch_id => 11, :source_id => new_camera.id, :source_type => "Camera")
new_camera = Camera.create(:branch_id => 11, :name => "teller2-furu-merapent", :address => "http://teller2-furu.deich.folkebibl.no/", :user => "secret", :pw => "secret")
Counter.create(:branch_id => 11, :source_id => new_camera.id, :source_type => "Camera")
new_camera = Camera.create(:branch_id => 11, :name => "teller3-furu-andre", :address => "http://teller3-furu.deich.folkebibl.no/", :user => "secret", :pw => "secret")
Counter.create(:branch_id => 11, :source_id => new_camera.id, :source_type => "Camera")
rescue => e
puts e.message
end
......@@ -15,6 +15,7 @@ ActiveRecord::Schema.define(version: 0) do
create_table "accumulated_branches", id: :integer, force: :cascade do |t|
t.string "name", limit: 30, null: false
t.string "branch_code"
t.date "first_active_date"
end
create_table "active_schedules", id: :integer, force: :cascade do |t|
......@@ -27,11 +28,6 @@ ActiveRecord::Schema.define(version: 0) do
t.string "branch_code"
end
create_table "camera_interfaces", id: :integer, force: :cascade do |t|
t.string "name", null: false
t.string "description", limit: 1024
end
create_table "cameras", id: :integer, force: :cascade do |t|
t.string "name", limit: 40, null: false
t.string "address", limit: 100, null: false
......@@ -72,12 +68,11 @@ ActiveRecord::Schema.define(version: 0) do
create_table "counts", id: :integer, force: :cascade do |t|
t.integer "counter_id", null: false
t.date "date", null: false
t.time "time", null: false
t.integer "visitors_in", limit: 2, default: 0, unsigned: true
t.integer "visitors_out", limit: 2, default: 0, unsigned: true
t.string "oh_code", limit: 1
t.boolean "is_primary_source", default: true
t.datetime "datetime", default: "2000-01-01 00:00:00", null: false
end
create_table "downtimes", id: :integer, force: :cascade do |t|
......@@ -105,17 +100,6 @@ ActiveRecord::Schema.define(version: 0) do
t.integer "active_schedule_id", null: false
end
create_table "overlapping_counters", id: :integer, force: :cascade do |t|
t.integer "overlap_id", null: false
t.integer "counter_id", null: false
t.string "description"
end
create_table "overlaps", id: :integer, force: :cascade do |t|
t.string "name", null: false
t.string "description"
end
create_table "pending_hours", id: :integer, force: :cascade do |t|
t.integer "weekday_id", limit: 2, null: false, unsigned: true
t.time "morning_start"
......@@ -146,9 +130,16 @@ ActiveRecord::Schema.define(version: 0) do
t.string "description"
end
create_table "source_types", id: :integer, force: :cascade do |t|
t.string "name", limit: 30, null: false
t.string "description"
create_table "processed_counts", id: :integer, force: :cascade do |t|
t.integer "counter_id", null: false
t.datetime "datetime"
t.integer "visitors_in_raw", default: 0, null: false
t.integer "visitors_out_raw", default: 0, null: false
t.integer "visitors_in", default: 0, null: false
t.integer "visitors_out", default: 0, null: false
t.boolean "is_primary_source", null: false
t.string "oh_code", limit: 1
t.integer "count_correction_id"
end
create_table "statistics_views", id: :integer, force: :cascade do |t|
......@@ -176,6 +167,9 @@ ActiveRecord::Schema.define(version: 0) do
t.integer "extended_total", default: 0, null: false
t.boolean "dirty_bit", default: true
t.boolean "is_missing_record"
t.integer "visitors_in_raw", default: 0, null: false
t.integer "visitors_out_raw", default: 0, null: false
t.integer "visitors_total_raw", default: 0, null: false
end
create_table "status", id: :integer, force: :cascade do |t|
......@@ -191,4 +185,5 @@ ActiveRecord::Schema.define(version: 0) do
add_foreign_key "entrances", "branches", name: "entrances_ibfk_1"
add_foreign_key "primary_source_periods", "counters", name: "primary_source_periods_ibfk_1"
add_foreign_key "primary_source_periods", "entrances", name: "primary_source_periods_ibfk_2"
add_foreign_key "processed_counts", "counters", name: "processed_counts_ibfk_1"
end
# encoding: utf-8
class GraphTemplates
def self.net_visitors(graph)
script = <<HERE
options.series = [];
options.chart.type = 'areaspline'
var stats = graph[dateString];
options.series = stats.series;
var total_in = stats.totals.in;
var total_out = stats.totals.out;