Browse Source

original post

tags/grid_before_module
commit
58e6cf84ac
  1. 2
      .gitignore
  2. 5
      README.markdown
  3. 269
      config.ru
  4. 89
      public/css/main.css
  5. 8
      public/css/mozilla.css
  6. 12
      public/css/webkit.css
  7. BIN
      public/img/favicon.ico
  8. 47
      public/index.html
  9. 62
      public/js/index.js
  10. 19
      public/js/jquery-1.3.1.min.js
  11. 97
      public/js/jquery.cookie.js
  12. 132
      rubyzome/controllers/Helpers.rb
  13. 48
      rubyzome/controllers/RestController.rb
  14. 40
      rubyzome/controllers/ServiceRestController.rb
  15. 40
      rubyzome/lib/Rubyzome.rb
  16. 2
      rubyzome/lib/RubyzomeError.rb
  17. 12
      rubyzome/models/Account.rb
  18. 12
      rubyzome/models/User.rb
  19. 99
      rubyzome/scripts/db/populate
  20. 13
      rubyzome/scripts/db/reset
  21. 12
      rubyzome/scripts/db/setup
  22. 122
      rubyzome/views/HTMLView.rb
  23. 11
      rubyzome/views/JSONView.rb
  24. 17
      rubyzome/views/RestView.rb
  25. 62
      rubyzome/views/XMLView.rb
  26. 33
      rubyzome/views/html/templates/main.erb
  27. 0
      tmp/restart.txt

2
.gitignore

@ -0,0 +1,2 @@
*.swp
.DS_Store

5
README.markdown

@ -0,0 +1,5 @@
# gpadm Project for GridPocket©
Using the *lyframework* usable with a free license.
This repository/branch contain the admin part of the project.

269
config.ru

@ -0,0 +1,269 @@
# The code in this file is part of the Rubyzome framework
# Rubyzome framework belongs to Luc Juggery and Yann Esposito
require 'rubygems'
require 'rack'
# TODO: find a better way to manage $view, may be using Rubyzome module
# n.b.: load the entire local application (/app files)
require 'rubyzome/lib/Rubyzome.rb'
# ----------------------------
# -- specific configuration --
# TODO: make a file containing central configuration only
# beware the name will not match one of
# a REST resource of the application
$directory_of_website='/website'
# -- end of specific configuration --
# -----------------------------------
module RestfulDispatcher
@view = nil
# Select the view to be used to render the object
def selectView(model,path)
# If it is a file of a website which is required then use the file load
if path.empty? or path =~ /^#{$directory_of_website}\//
return nil?
end
# View used is based upon request's last characters
# .html => HTMLView
# .json => JSONView
# .xml => XMLView
type = File.extname(path)
if type.empty?
type = 'html'
else
type.slice!(0)
end
view_name=%{/#{type.downcase}/}
# if request on a specific ressource
if path.split('/').length % 2 != 0
# check Single Ressource Type Specific View
# eg: /stats/history.xml will render using
# /app/views/xml/HistoryStatXMLView
specific_object=File.basename(path, ".#{type}").capitalize
view_name<<=%{#{specific_object}#{model}#{type.upcase}View}
puts %{try view = #{view_name}}
if $views.has_key?(view_name)
@view=$views[view_name].new
puts %{selected view = #{view_name}}
return
end
else
# check Plural Ressource Specific View
# eg: /stats.xml will render using
# app/views/xml/StatsXMLView
view_name<<=%{#{model}s#{type.upcase}View}
puts %{try view = #{view_name}}
if $views.has_key?(view_name)
@view=$views[view_name].new
puts %{selected view = #{view_name}}
return
end
end
# Check Type Generic View
# eg: /users.xml will render using
# app/view/XMLView
view_name = %{#{type.upcase}View}
puts %{try view = #{view_name}}
if $views.has_key?(view_name)
@view=$views[view_name].new
puts %{selected view = #{view_name}}
return
end
puts %{no view selected}
# No view found...
return nil
end
# Nice html error (404 by default)
def htmlError(e, controller_name, function_name)
pref="<tr><td><code>"
suff="</tr></td></code>"
[ 404,
{'Content-Type' => 'text/html', 'charset'=>'UTF-8'},
$views['HTMLView'].new.httpContent(
{
:html_title => '404',
:html_subtitle => %{<code>#{controller_name}::#{function_name}</code>},
:html_content => %{<h3>Exception</h3>
<code>#{e.message}</code>
<h3>Backtrace</h3>
<table>#{pref}#{e.backtrace.join(suff+pref)}#{suff}</table>}
} )
]
end
# Fonction triggered for each HTTP request
def call(env)
# Request holds all HTTP parameters
request = Rack::Request.new(env)
# dispatcher returns:
# name of the model,
# name of the model's controller and
# name of the controller's function to call
model_name, controller_name, function_name = dispatcher_class(request)
# Set the view to be used
selectView(model_name,request.path)
# Call right method on right controller
# (if request is HTTP GET, body is the result of the 'get' method of the controller)
begin
# If no view selected, try to load the file associated to the path
if @view.nil?
begin
# third choice, prefer loading file
file=File.new('/public'+path,'r')
# load the content of the file in memory
# may be not the best way to do that
# TODO: caching issue for file who didn't changed
# may be pushing all file content into memory
# for faster usage is the first naive method
content = file.collect
file.close
# MIME Type get
head={ 'Content-Type' => MIME::Types.of('file')[0].to_s }
return [200, head, content ]
rescue
return [404,
@view['HTMLView'].head,
@view.httpContent({
:html_title => '404',
:html_subtitle => 'File not found',
:html_content => %{file #{path} not found! You should dig arround.}})]
end
else
# Controller creation and init with current request
# Call requested function
begin
body = Kernel.const_get(controller_name).new(request).send function_name
rescue GridError => e
return [500,
@view.head,
@view.httpContent({
:html_title => '500',
:html_subtitle => e.message,
:html_content => e.message})]
end
if @view.respond_to?(:request)
@view.request=request
end
return [200, @view.head, @view.httpContent(body) ]
end
# Resource not found
rescue Exception => e
htmlError(e, controller_name, function_name)
end
end
# renvoie une nouvelle instance de sa propre classe
# avec l'objet request mis correctement
# /users/nickname/events/32?user='my_nickname'&password='PaSsW0rc|'
# -> EventController
# avec en paramètres GET+POST params
# + event_id='32'
# + user_id='nickname'
def dispatcher_class(request)
path=request.path
# Remove path extension (.json or .xml for example)
type=File.extname(path)
path.chomp!(type)
type.slice!(0)
classname=''
modelname = ''
last_class_id=''
function_name=''
i=0
path.split('/').each do |chemin|
if chemin == ''
next
end
if i%2==0
classname = chemin[0..-2].capitalize + 'Controller'
modelname = chemin[0..-2].capitalize
last_class_id=chemin[0..-2]+'_id'
if request.get?
function_name=:index
elsif request.post?
if request[:_method].nil?
function_name=:create
else
case request[:_method]
when 'OPTIONS'
function_name=:options
else
function_name=:bad_request
end
request.delete[:_method]
end
else
if request.request_method == 'OPTIONS'
function_name=:options
else
function_name=:bad_request
end
end
else
# on ajoute la valeur dans les paramètre
# en fonction du chemin
# /objects/toto --> request[objects_id]='toto'
request[last_class_id]=chemin
# dispatche la fonction a appeler en fonction
# du type de requête.
if request.get?
function_name=:show
elsif request.put?
function_name=:update
elsif request.delete?
function_name=:delete
elsif request.post?
if request[:_method].nil?
function_name=:bad_request
else
case request[:_method]
when 'OPTIONS'
function_name=:options
when 'PUT'
function_name=:update
when 'DELETE'
function_name=:delete
else
function_name=:bad_request
end
request.delete[:_method]
end
else
if request.request_method == 'OPTIONS'
function_name=:options
else
function_name=:bad_request
end
end
end
i+=1
end
return modelname, classname, function_name
end
end
class Main
include RestfulDispatcher
end
run Main.new

89
public/css/main.css

@ -0,0 +1,89 @@
html, body {
margin: 0;
padding: 0;
top: 0;
left: 0;
}
body {
background-color: #320;
color: #ca8;
}
#entete {
background-color: #320;
margin: 0;
padding: 1em;
text-align: center;
text-shadow: 0 0 9px #100;
}
#content {
border-top: 1px solid #db8;
border-bottom: 1px solid #eda;
background-color: #ca8;
color: #320;
text-align: center;
padding-top: 3em;
padding-bottom: 3em;
}
#bottom {
font-size: .8em;
text-align: center;
padding-top: 3em;
background-color: #320;
color: #ca8;
padding-bottom: 3em;
}
a,
a:link,
a:visited {
color: #fda; }
a:hover,
a:active {
color: #d70; }
#gprefs {
font-size: 1.2em;
margin: 1em;
}
#promotion {
font-size: .8em;
}
/* input */
#content input {
color: #320;
margin: .5em;
font-size: 1.5em;
}
#content input.inactive {
color: #dddddd;
}
#signin {
width: 10em;
}
/* tables */
table {
margin-left: auto;
margin-right: auto;
text-align: left; }
table tr th {
margin: 7px;
color: #ca8;
background-color: #320;
}
table tr th {
font-weight: bold;
text-align: center;
padding: 1.5em; }
table tr td {
padding: .8em;
border: solid 1px #320; }
table tr.r0 {
background-color: #e8c6a0;
}

8
public/css/mozilla.css

@ -0,0 +1,8 @@
#entete, #bottom {
background: -moz-radial-gradient(center center, 0, center center, 300, from(#531), to(#320) ) no-repeat;
}
#bottom {
-moz-box-shadow: 0px 10px 10px rgba(6,4,0,.3);
margin-left: 10px;
margin-right: 10px;
}

12
public/css/webkit.css

@ -0,0 +1,12 @@
#entete {
background-image: -webkit-gradient(radial, center bottom, 0, center bottom, 300, from(#531), to(#320) );
}
#content {
background-image: -webkit-gradient(radial, center top, 0, center top, 300, from(#fdb), to(#ca8) );
}
#bottom {
background-image: -webkit-gradient(radial, center center, 0, center center, 300, from(#531), to(#320) );
-webkit-box-shadow: 0px 10px 10px rgba(6,4,0,.3);
margin-left: 10px;
margin-right: 10px;
}

BIN
public/img/favicon.ico

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

47
public/index.html

@ -0,0 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="fr" xml:lang="fr">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="shortcut icon" type="image/x-icon" href="/img/favicon.ico" />
<link rel="stylesheet" type="text/css" href="./css/main.css" />
<script type="text/javascript" src="./js/jquery-1.3.1.min.js"></script>
<script type="text/javascript" src="./js/jquery.cookie.js"></script>
<script type="text/javascript" src="./js/index.js"></script>
<title>Rubyzome</title>
</head>
<body>
<div id="entete">
<h1>Rubyzome</h1>
<h2>Sign in</h2>
</div>
<div id="content">
<form action="#" method="GET">
<div id="usernameblock">
<input name="username" type="text" id="username" value="User Name" class="inactive" />
</div>
<div id="passwordblock">
<input name="password" type="password" id="password" value="password" class="inactive" />
</div>
<div id="remember">
<input name="signin" type="checkbox" id="checkbox" value="Sign in" />
<label>Remember me on this computer</label>
</div>
<div id="signinbutton">
<input name="signin" type="submit" id="signin" value="Sign in" />
</div>
</form>
</div>
<div id="bottom">
<div id="gprefs">
2009 GridPocket© SAS All Rights Reserved
</div>
<div id="promotion">
Designed by <a href="http://yannesposito.com">Yann Esposito</a> &amp; <a href="http://lucarea.com">Luc Juggery</a>.
</div>
</div>
</body>
</html>

62
public/js/index.js

@ -0,0 +1,62 @@
var user = "";
var password = "";
function enter_next_stage() {
return false;
}
function getUserFromCookie() {
user = $.cookie('user');
if (user) {
password = $.cookie('password');
$('#username').val(user).become_active();
$('#password').val(password).become_active();
enter_next_stage();
}
}
function become_active() {
$(this).removeClass('inactive');
}
function signin() {
if ( $('#remember input:checkbox').is(':checked') ) {
$.cookie('user', user, {path:'/'});
$.cookie('password', password, {path:'/'});
}
enter_next_stage();
}
function setSpecificCss() {
var userAgent = navigator.userAgent.toLowerCase();
if ( /webkit/.test(userAgent) ) {
$('head').append('<link rel="stylesheet" href="/css/webkit.css"/>');
} else if ( /mozilla/.test(userAgent) ) {
$('head').append('<link rel="stylesheet" href="/css/mozilla.css"/>');
}
}
// after document loaded
$(document).ready(function(){
getUserFromCookie();
setSpecificCss();
$('#username').click(become_active);
$('#password').click(become_active);
$('#username').focus(become_active);
$('#password').focus(become_active);
$('#username').change(function(){
if ( $(this).val() == '' ) {
$(this).val('User Name');
$(this).addClass('inactive');
}
});
$('#password').change(function(){
if ( $(this).val() == '' ) {
$(this).val('password');
$(this).addClass('inactive');
}
});
$('#signin').click( signin );
});

19
public/js/jquery-1.3.1.min.js

File diff suppressed because one or more lines are too long

97
public/js/jquery.cookie.js

@ -0,0 +1,97 @@
/**
* Cookie plugin
*
* Copyright (c) 2006 Klaus Hartl (stilbuero.de)
* Dual licensed under the MIT and GPL licenses:
* http://www.opensource.org/licenses/mit-license.php
* http://www.gnu.org/licenses/gpl.html
*
*/
/**
* Create a cookie with the given name and value and other optional parameters.
*
* @example $.cookie('the_cookie', 'the_value');
* @desc Set the value of a cookie.
* @example $.cookie('the_cookie', 'the_value', { expires: 7, path: '/', domain: 'jquery.com', secure: true });
* @desc Create a cookie with all available options.
* @example $.cookie('the_cookie', 'the_value');
* @desc Create a session cookie.
* @example $.cookie('the_cookie', null);
* @desc Delete a cookie by passing null as value. Keep in mind that you have to use the same path and domain
* used when the cookie was set.
*
* @param String name The name of the cookie.
* @param String value The value of the cookie.
* @param Object options An object literal containing key/value pairs to provide optional cookie attributes.
* @option Number|Date expires Either an integer specifying the expiration date from now on in days or a Date object.
* If a negative value is specified (e.g. a date in the past), the cookie will be deleted.
* If set to null or omitted, the cookie will be a session cookie and will not be retained
* when the the browser exits.
* @option String path The value of the path atribute of the cookie (default: path of page that created the cookie).
* @option String domain The value of the domain attribute of the cookie (default: domain of page that created the cookie).
* @option Boolean secure If true, the secure attribute of the cookie will be set and the cookie transmission will
* require a secure protocol (like HTTPS).
* @type undefined
*
* @name $.cookie
* @cat Plugins/Cookie
* @author Klaus Hartl/klaus.hartl@stilbuero.de
*/
/**
* Get the value of a cookie with the given name.
*
* @example $.cookie('the_cookie');
* @desc Get the value of a cookie.
*
* @param String name The name of the cookie.
* @return The value of the cookie.
* @type String
*
* @name $.cookie
* @cat Plugins/Cookie
* @author Klaus Hartl/klaus.hartl@stilbuero.de
*/
jQuery.cookie = function(name, value, options) {
if (typeof value != 'undefined') { // name and value given, set cookie
options = options || {};
if (value === null) {
value = '';
options = $.extend({}, options); // clone object since it's unexpected behavior if the expired property were changed
options.expires = -1;
}
var expires = '';
if (options.expires && (typeof options.expires == 'number' || options.expires.toUTCString)) {
var date;
if (typeof options.expires == 'number') {
date = new Date();
date.setTime(date.getTime() + (options.expires * 24 * 60 * 60 * 1000));
} else {
date = options.expires;
}
expires = '; expires=' + date.toUTCString(); // use expires attribute, max-age is not supported by IE
}
// NOTE Needed to parenthesize options.path and options.domain
// in the following expressions, otherwise they evaluate to undefined
// in the packed version for some reason...
var path = options.path ? '; path=' + (options.path) : '';
var domain = options.domain ? '; domain=' + (options.domain) : '';
var secure = options.secure ? '; secure' : '';
document.cookie = [name, '=', encodeURIComponent(value), expires, path, domain, secure].join('');
} else { // only name given, get cookie
var cookieValue = null;
if (document.cookie && document.cookie != '') {
var cookies = document.cookie.split(';');
for (var i = 0; i < cookies.length; i++) {
var cookie = jQuery.trim(cookies[i]);
// Does this cookie string begin with the name we want?
if (cookie.substring(0, name.length + 1) == (name + '=')) {
cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
break;
}
}
}
return cookieValue;
}
};

132
rubyzome/controllers/Helpers.rb

@ -0,0 +1,132 @@
module Helpers
### AUTHENTICATION ###
def check_authentication
# if(/gpadm/.match($0) != nil) then
if @request[:l] != 'adm' then
raise GridError, "Only admin is authorized to perform this action"
end
if @request[:p] != 'adm' then
raise GridError, "Authentication failed, please check your login and password"
end
# else
# user=User.first({:nickname => @request[:l]})
# if user.nil?
# raise GridError, "Authentication failed, user with login #{@request[:l]} does not exist"
# end
# if(@request[:p] != Account.first({:user => user}).password) then
# raise GridError, "Authentication failed, please check username and password"
# end
# end
end
### ACCOUNT STUFF ###
def get_account(id=:account_id)
account_id = @request[id]
if(account_id.nil?) then
raise GridError, "No user provided"
end
user = User.first({:nickname => account_id})
if(user.nil?) then
raise GridError, "User #{account_id} does not exist"
end
account = user.account
if(account.nil?) then
raise GridError, "No account linked to user #{user_id}"
end
return account
end
### USER STUFF ###
def get_user(id=:user_id)
user_id = @request[id]
if(user_id.nil?) then
raise GridError, "No user provided"
end
user = User.first({:nickname => user_id})
if(user.nil?) then
raise GridError, "User #{user_id} does not exist"
end
return user
end
### SENSOR STUFF ###
def get_sensor(id=:sensor_id)
sensor_id = @request[id]
if(sensor_id.nil?) then
raise GridError, "No sensor provided"
end
sensor = Sensor.first({:sensor_hr => sensor_id})
if(sensor.nil?) then
raise GridError,"Sensor #{sensor_id} does not exist"
end
return sensor
end
### MEASURE STUFF ###
def get_measure(id=:measure_id)
measure_id = @request[id]
if(measure_id.nil?) then
raise GridError, "No measure provided"
end
measure = Measure.first({:measure_hr => measure_id})
if(measure.nil?) then
raise GridError,"Measure #{measure_id} does not exist"
end
return measure
end
### OWNERSHIP ###
def check_ownership_user_account(user,account)
if account.user_id = user
raise GridError, "Account is not linked to user #{user.nickname}"
end
end
def check_ownership_user_sensor(user,sensor)
if sensor.user != user then
raise GridError, "Sensor #{sensor.sensor_hr} does not belong to User #{user.nickname}"
end
end
def check_ownership_sensor_measure(sensor,measure)
if measure.sensor != sensor then
raise GridError, "Measure #{measure.measure_hr} does not belong to Sensor #{sensor.sensor_hr}"
end
end
### ONLY USED IN USER PART ###
def check_ownership_requestor_user(requestor,user)
if requestor.nickname != user.nickname
raise GridError, "Requestor #{requestor.nickname} and user requested #{user.nickname} do not match"
end
end
### UTIL ###
def clean_id(hash)
hash.delete(:id)
hash.delete(:user_id)
hash.delete(:account_id)
hash.delete(:sensor_id)
hash
end
### STAT PURPOSES ###
def get_start_date
days_nbr = 1
days_nbr = @request[:days_nbr] if not @request[:days_nbr].nil?
start_date = DateTime.now - days_nbr.to_i
return start_date
end
end

48
rubyzome/controllers/RestController.rb

@ -0,0 +1,48 @@
class RestController
# Use helpers module
require "app/controllers/include/Helpers.rb"
include Helpers
# ajoute un attribut Request
# contenant les détails des requêtes
attr_accessor :request
# on initialise avec un objet requête
def initialize(req)
@request=req
end
def bad_request
raise GridError, "Bad request, please refer to options"
end
def clean_hash( tab )
hash={}
tab.each do |t|
if not @request[t].nil?
hash[t]=@request[t]
end
end
hash
end
# Action not available
def action_not_available
raise GridError, "This action is not available"
end
# Action completed
def action_completed(message)
{:message => message}
end
# Mandatory params check
def check_mandatory_params(mandatory_params)
mandatory_params.each do |param|
if @request["#{param}"].nil? then
raise GridError.new("Mandatory parameter [#{param}] must be provided")
end
end
end
end

40
rubyzome/controllers/ServiceRestController.rb

@ -0,0 +1,40 @@
require 'rubyzome/controllers/RestController.rb'
class ServiceRestController < RestController
def service_name
@request[ (self.class.to_s.gsub(/Controller/,'').downcase + '_id' ).intern ].intern
end
def show
if services[:show].include?(service_name)
self.send(service_name)
else
raise GridError, "Service #{service_name} not available"
end
end
def update
if ( services[:update].include?(service_name) )
self.send(service_name)
else
raise GridError, "Service #{service_name} not available"
end
end
def index
if services.empty?
raise GridError, "No service available"
end
services[:index].map { |service|
self.send(service)
}
end
# example
# return { :index => [:completed] ,
# :put => [:complete] }
def services
return {}
end
end

40
rubyzome/lib/Rubyzome.rb

@ -0,0 +1,40 @@
require 'dm-core'
Dir["rubyzome/lib/*.rb"].each { |file| require file }
Dir["rubyzome/controllers/*.rb"].each { |file| require file }
$views={}
Dir["rubyzome/views/*.rb"].each do |file|
require file
if file == "/rubyzome/views/RestView.rb"
next
end
viewname=File.basename(file,File.extname(file))
$views[viewname]=Kernel.const_get(viewname)
end
# TODO: sanitize models
# Dir["rubyzome/models/*.rb"].each { |file| require file }
# TODO: sanitize helpers
# Dir["rubyzome/helpers/*.rb"].each { |file| require file }
# ------ Load local application -----
# Include application custom classes (Error, Util, ...)
require 'app/controllers/include/Helpers.rb'
# Include all controllers
Dir["app/controllers/*.rb"].each { |file| require file }
# Include all specific views (if any)
Dir["app/views/*/*.rb"].each do |file|
require file
viewname=File.basename(file,File.extname(file))
typename=File.basename(File.dirname(file))
$views['/'+typename+'/'+viewname]=Kernel.const_get(viewname)
end
# Include all models
Dir["app/models/*.rb"].each { |file| require file }
# TODO: centralize datamapper configuration infos
DataMapper.setup(:default, 'mysql://gridadmin:gridadmin@localhost/grid')

2
rubyzome/lib/RubyzomeError.rb

@ -0,0 +1,2 @@
class GridError < StandardError
end

12
rubyzome/models/Account.rb

@ -0,0 +1,12 @@
class RubyzomeAccount
# Includes
include DataMapper::Resource
# Properties
property :id, Serial
property :password, String
# Associations
belongs_to :user
end

12
rubyzome/models/User.rb

@ -0,0 +1,12 @@
class RubyzomeUser
# Includes
include DataMapper::Resource
# Properties
property :id, Serial
property :nickname, String
# Associations
has 1, :account, :model => "Account"
end

99
rubyzome/scripts/db/populate

@ -0,0 +1,99 @@
#!/usr/bin/env ruby
require 'rubygems'
require 'dm-core'
# require 'date'
require 'time'
require 'faker'
# inclusion de tous les modèles
Dir["../../app/models/*.rb"].each { |file| require file }
# connexion à la base de donnée
DataMapper.setup(:default, 'mysql://gridadmin:gridadmin@localhost/grid')
# Comment that could be added by admin, based on user average consumption
comments = {
0..500 => "Very low consumption",
501..1000 => "Low consumption",
1001..1500 => "Normal consumption",
1501..2000 => "Medium consumption",
2001..2500 => "Consumption quite high",
2501..3000 => "High consumption, please reduce it :-)"
}
# User creation
nb_users=30
(1..nb_users).each do |user_nb|
# Get dummy
# - firstname
# - lastname
# - email
# - nickname
# - country
# - zip code
# - city
# - street
firstname = Faker::Name.first_name
lastname = Faker::Name.last_name
nickname = "#{firstname.downcase}#{lastname.downcase}"
# puts "User #{user_nb}:#{nickname}"
user_hash = { :nickname => "#{nickname}",
:status => "" }
account_hash = {:firstname => "#{firstname}",
:lastname => "#{lastname}",
:email => "#{firstname.downcase}.#{lastname.downcase}@yahoo.com",
:password => "guest",
:country => "US",
:zip => Faker::Address.zip_code,
:city => Faker::Address.city,
:street => Faker::Address.street_address}
# Create user entry
user = User.new(user_hash)
user.save
# Create account entry
account_hash[:user] = user
account=Account.new(account_hash)
account.save
# Create sensors for each users
nb_sensors=3
(1..nb_sensors).each do |sensor_nb|
# puts "Sensor:#{sensor_nb}"
sensor=Sensor.new( :sensor_hr => "#{nickname}_#{sensor_nb}",
:description => "Sensor #{sensor_nb} of #{firstname} #{lastname}",
:address => "Same as user",
:user => user)
sensor.save
# Create measure for each sensor: one measure each 30 minutes for the past 2 days
nb_measures=96
total = 0
(1..nb_measures).each do |measure_nb|
# puts "Measure:#{measure_nb}"
d = Time.now - measure_nb * 5 * 60
measure = Measure.new( :measure_hr => "#{nickname}_#{sensor_nb}_#{measure_nb}",
:date => d,
:consumption => rand(3000),
:sensor => sensor)
measure.save
total = total + measure.consumption.to_f
end
# Get measure average
average = total / nb_measures
# Set comment to user depending upon his average consumption
comment = ""
comments.each do |k,v|
if k.include?(average) then
comment = v
end
end
user.status = comment
user.save
end
end

13
rubyzome/scripts/db/reset

@ -0,0 +1,13 @@
#!/usr/bin/env ruby
require 'rubygems'
require 'dm-core'
require 'benchmark'
require 'date.rb'
# Include all models
Dir["../app/models/*.rb"].each { |file| require file }
# Connect to DB
DataMapper.setup(:default, 'mysql://gridadmin:gridadmin@localhost/grid')
# Reset tables
DataMapper.auto_migrate!

12
rubyzome/scripts/db/setup

@ -0,0 +1,12 @@
name=grid;
mysql -u root -p <<END
CREATE DATABASE $name;
CREATE USER '${name}admin'@'localhost' IDENTIFIED BY '${name}admin';
CREATE USER '${name}admin'@'127.0.0.1' IDENTIFIED BY '${name}admin' ;
GRANT ALL on $name.* TO '${name}admin'@'localhost' ;
GRANT ALL on $name.* TO '${name}admin'@'127.0.0.1' ;
CREATE USER '$name'@'localhost' IDENTIFIED BY '$name' ;
CREATE USER '$name'@'127.0.0.1' IDENTIFIED BY '$name' ;
GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP on $name.* TO '$name'@'localhost';
GRANT SELECT,INSERT,UPDATE,DELETE,CREATE,DROP on $name.* TO '$name'@'127.0.0.1';
END

122
rubyzome/views/HTMLView.rb

@ -0,0 +1,122 @@
# La classe pour renvoyer les valeurs en HTML
require 'erubis'
require 'rubyzome/views/RestView.rb'
class HTMLView < RestView
attr_accessor :request
# make @template a class variable and not
# a complete class hierarchy variable (as @@var are)
class << self
attr_accessor :template
end
def template
self.class.template
end
def initialize
@head = {'Content-Type' => 'text/html', 'charset' => 'UTF-8' }
end
# Protect special chars
def protectHTML(content)
content.gsub('&','&amp;').gsub('<','&lt;').gsub('>','&gt;')
end
def is_array_of_hashes?(object)
if not object.is_a?(Array)
return false
end
object.each do |x|
if not x.is_a?(Hash)
return false
end
end
return true
end
# An Array to HTML table
def array_to_HTML(object)
res=''
if is_array_of_hashes?(object)
keys = Array.new
object.each { |x| keys |= x.keys }
res <<= '<tr>'
keys.each { |k| res <<= '<th>' + html_repr(k) + '</th>' }
res <<= '</tr>'
parity_class=0
object.each do |h|
parity_class=( parity_class+1 ) % 2
res <<= %{<tr class="r#{parity_class}">}
keys.each do |k|
if h.has_key?(k)
res<<= %{<td>#{html_repr( h[k] )}</td>}
else
res<<= %{<td></td>}
end
end
res <<= '</tr>'
end
else
object.each do |o|
res <<= '<tr><td>' + html_repr(o) + '</td></tr>'
end
end
'<table>'+res+'</table>'
end
# An Hash to HTML table (with two columns)
def hash_to_HTML(object)
res=''
parity_class=0
object.each do |k,v|
parity_class=( parity_class+1 ) % 2
res <<= %{<tr class="r#{parity_class}"><td>} + html_repr(k) +
'</td><td>'+ html_repr(v) +'</td></tr>'
end
'<table>'+res+'</table>'
end
# from Hash or Array to HTLM table
def html_repr(object)
case object
when Array then return array_to_HTML(object)
when Hash then return hash_to_HTML(object)
else return object.to_s
end
end
def init_titles_from(object)
if object.class == Hash and object.has_key?(:html_content)
if object.has_key?(:html_title)
@title=object[:html_title]
else
@title="Error"
end
if object.has_key?(:html_subtitle)
@subtitle=object[:html_subtitle]
else
@subtitle="404"
end
@content=object[:html_content]
else
@content=html_repr(object)
if not request.nil?
@title=File.basename(request.path)
@subtitile=request.path
end
end
end
def render
Erubis::Eruby.new(template).result(binding())
end
# Handle content
def content(object)
init_titles_from(object)
render
end
end
# TODO: think to create a Rubyzome contant Rubyzome::Views::TemplateDir
HTMLView.template=File.read('rubyzome/views/html/templates/main.erb')

11
rubyzome/views/JSONView.rb

@ -0,0 +1,11 @@
require 'json'
require 'rubyzome/views/RestView.rb'
class JSONView < RestView
def initialize
@head = {'Content-Type' => 'application/json', 'charset' => 'UTF-8' }
end
def content(object)
JSON object
end
end

17
rubyzome/views/RestView.rb

@ -0,0 +1,17 @@
class RestView
attr_accessor :head
attr_accessor :code_return
def init_code_return_from_object(object)
if object.class == Hash and object.has_key?(:error)
@code_return = object[:error]
object.delete(:error)
else
@code_return = 200
end
end
def httpContent(object)
init_code_return_from_object(object)
self.content(object)
end
end

62
rubyzome/views/XMLView.rb

@ -0,0 +1,62 @@
require 'nokogiri'
require 'rubyzome/views/RestView.rb'
# Class used to send back XML
class XMLView < RestView
def initialize
@head = {'Content-Type' => 'text/xml', 'charset' => 'UTF-8' }
end
# Protect XML special characters
def protectXML(content)
content.gsub('&','&amp;').gsub('<','&lt;').gsub('>','&gt;')
end
# Create XML file with the list of items provided in content
# Exemple:
# <data>
# <item>
# <field_name>field_value</field_name>
# <field_name>field_value</field_name>
# ...
# <item>
# <field_name>field_value</field_name>
# <field_name>field_value</field_name>
# ...
# </item>
# ...
# </data>
def content(content)
# Buid new xml document
document = Nokogiri::XML::Document.new
# Add root node
data = Nokogiri::XML::Node.new("data",document)
document.root = data
# Check if content is an Hash or an Array
if content.instance_of?Hash then
xml_node = build_item(content,document)
data.add_child(xml_node)
elsif content.instance_of?Array then
content.each do |item|
xml_node = build_item(item,document)
data.add_child(xml_node)
end
end
return document.to_s.gsub(/\\n/,"")
end
# Build item that will be inserted in the tree structure
def build_item(item,doc)
xml_item = Nokogiri::XML::Node.new("item",doc)
# Loop through each attributes of item
item.each do |k,v|
new_node = Nokogiri::XML::Node.new("#{k}",doc)
new_node.content = v
xml_item.add_child(new_node)
end
xml_item
end
end

33
rubyzome/views/html/templates/main.erb

@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" lang="fr" xml:lang="fr">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<link rel="shortcut icon" type="image/x-icon" href="/img/favicon.ico" />
<link rel="stylesheet" type="text/css" href="/css/main.css" />
<script type="text/javascript" src="/js/jquery-1.3.1.min.js"></script>
<script type="text/javascript" src="/js/jquery.cookie.js"></script>
<script type="text/javascript" src="/js/index.js"></script>
<title><%= @title %></title>
</head>
<body>
<div id="entete">
<h1><%= @title %></h1>
<h2><%= @subtitle %></h2>
</div>
<div id="content">
<%= @content %>
</div>
<div id="bottom">
<div id="gprefs">
2009 GridPocket© SAS All Rights Reserved
</div>
<div id="promotion">
Designed by <a href="http://yannesposito.com">Yann Esposito</a> &amp; <a href="http://lucarea.com">Luc Juggery</a>.
</div>
</div>
</body>
</html>

0
tmp/restart.txt

Loading…
Cancel
Save