Permalink
Browse files

Merging in acts_as_authenticated (restful_authentication) branch

  • Loading branch information...
2 parents 453f118 + 9b33d1a commit db14751836c4f040cd145659239840cfb61927a6 @adamhjk committed Nov 21, 2007
Showing with 2,249 additions and 215 deletions.
  1. +0 −4 TODO
  2. +4 −0 app/controllers/application.rb
  3. +12 −4 app/controllers/attribs_controller.rb
  4. +14 −6 app/controllers/avalues_controller.rb
  5. +8 −2 app/controllers/dashboard_controller.rb
  6. +11 −6 app/controllers/nodes_controller.rb
  7. +1 −0 app/controllers/options_controller.rb
  8. +53 −23 app/controllers/rest_nodes_controller.rb
  9. +4 −1 app/controllers/rest_search_controller.rb
  10. +3 −2 app/controllers/rest_tags_controller.rb
  11. +3 −0 app/controllers/search_controller.rb
  12. +37 −0 app/controllers/sessions_controller.rb
  13. +12 −5 app/controllers/tags_controller.rb
  14. +51 −0 app/controllers/users_controller.rb
  15. +2 −0 app/helpers/sessions_helper.rb
  16. +2 −0 app/helpers/users_helper.rb
  17. +8 −11 app/models/attrib.rb
  18. +7 −5 app/models/avalue.rb
  19. +64 −72 app/models/node.rb
  20. +6 −6 app/models/tag.rb
  21. +26 −0 app/models/user.rb
  22. +2 −2 app/views/attribs/edit.rhtml
  23. +1 −1 app/views/attribs/new.rhtml
  24. +2 −2 app/views/avalues/edit.rhtml
  25. +1 −1 app/views/avalues/new.rhtml
  26. +2 −1 app/views/dashboard/index.rhtml
  27. +1 −0 app/views/layouts/_footer.rhtml
  28. +8 −1 app/views/layouts/_header.rhtml
  29. +2 −0 app/views/layouts/_minimal_footer.rhtml
  30. +27 −0 app/views/layouts/_minimal_header.rhtml
  31. +6 −0 app/views/layouts/sessions.rhtml
  32. +6 −0 app/views/layouts/users.rhtml
  33. +4 −4 app/views/nodes/_attrib.rhtml
  34. +5 −1 app/views/nodes/_listing.rhtml
  35. +2 −2 app/views/nodes/edit.rhtml
  36. +2 −2 app/views/nodes/show.rhtml
  37. +2 −2 app/views/rest_nodes/_node.rxml
  38. +2 −2 app/views/rest_tags/_tag.rxml
  39. +14 −0 app/views/sessions/_form.rhtml
  40. +3 −0 app/views/sessions/new.rhtml
  41. +2 −0 app/views/tags/_all_tag_list.rhtml
  42. +6 −1 app/views/tags/_tagged_nodes.rhtml
  43. +1 −1 app/views/tags/new.rhtml
  44. +15 −0 app/views/users/_form.rhtml
  45. +6 −0 app/views/users/edit.rhtml
  46. +27 −0 app/views/users/index.rhtml
  47. +6 −0 app/views/users/new.rhtml
  48. +1 −1 bin/icagent
  49. +22 −2 bin/icpuppet
  50. +21 −2 bin/icsearch
  51. +1 −1 bin/icwatcher
  52. +17 −3 config/routes.rb
  53. +18 −0 db/migrate/006_create_users.rb
  54. +16 −0 db/migrate/007_create_admin_user.rb
  55. +11 −0 db/migrate/008_update_node_for_auth.rb
  56. +9 −0 db/migrate/009_update_nodes_add_quarantined.rb
  57. +9 −0 db/migrate/010_update_user_table_add_read_write.rb
  58. +19 −0 db/migrate/011_upgrade_node_objects.rb
  59. +19 −4 db/schema.rb
  60. +140 −0 lib/authenticated_system.rb
  61. +26 −0 lib/authenticated_test_helper.rb
  62. +29 −0 lib/authorized_as_user.rb
  63. +35 −10 lib/iclassify/agent.rb
  64. +22 −2 lib/iclassify/client.rb
  65. +3 −1 lib/iclassify/node.rb
  66. +54 −0 lib/password_encryption.rb
  67. +12 −0 public/stylesheets/iclassify.css
  68. +0 −12 spec/controllers/tags_controller_spec.rb
  69. +4 −0 spec/fixtures/nodes.yml
  70. +5 −7 spec/models/node_spec.rb
  71. +17 −0 test/fixtures/users.yml
  72. +85 −0 test/functional/sessions_controller_test.rb
  73. +65 −0 test/functional/users_controller_test.rb
  74. +101 −0 test/unit/user_test.rb
  75. +29 −0 vendor/plugins/restful_authentication/README
  76. +22 −0 vendor/plugins/restful_authentication/Rakefile
  77. +1 −0 vendor/plugins/restful_authentication/generators/authenticated/USAGE
  78. +218 −0 vendor/plugins/restful_authentication/generators/authenticated/authenticated_generator.rb
  79. +3 −0 vendor/plugins/restful_authentication/generators/authenticated/templates/activation.rhtml
  80. +127 −0 vendor/plugins/restful_authentication/generators/authenticated/templates/authenticated_system.rb
  81. +26 −0 ...or/plugins/restful_authentication/generators/authenticated/templates/authenticated_test_helper.rb
  82. +31 −0 vendor/plugins/restful_authentication/generators/authenticated/templates/controller.rb
  83. +17 −0 vendor/plugins/restful_authentication/generators/authenticated/templates/fixtures.yml
  84. +85 −0 vendor/plugins/restful_authentication/generators/authenticated/templates/functional_test.rb
  85. +2 −0 vendor/plugins/restful_authentication/generators/authenticated/templates/helper.rb
  86. +14 −0 vendor/plugins/restful_authentication/generators/authenticated/templates/login.rhtml
  87. +25 −0 vendor/plugins/restful_authentication/generators/authenticated/templates/mailer.rb
  88. +31 −0 vendor/plugins/restful_authentication/generators/authenticated/templates/mailer_test.rb
  89. +21 −0 vendor/plugins/restful_authentication/generators/authenticated/templates/migration.rb
  90. +98 −0 vendor/plugins/restful_authentication/generators/authenticated/templates/model.rb
  91. +30 −0 vendor/plugins/restful_authentication/generators/authenticated/templates/model_controller.rb
  92. +86 −0 vendor/plugins/restful_authentication/generators/authenticated/templates/model_functional_test.rb
  93. +2 −0 vendor/plugins/restful_authentication/generators/authenticated/templates/model_helper.rb
  94. +11 −0 vendor/plugins/restful_authentication/generators/authenticated/templates/observer.rb
  95. +16 −0 vendor/plugins/restful_authentication/generators/authenticated/templates/signup.rhtml
  96. +8 −0 vendor/plugins/restful_authentication/generators/authenticated/templates/signup_notification.rhtml
  97. +101 −0 vendor/plugins/restful_authentication/generators/authenticated/templates/unit_test.rb
  98. +1 −0 vendor/plugins/restful_authentication/install.rb
View
4 TODO
@@ -1,14 +1,10 @@
-* Allow for deleting a tag completely
* Write real tests. It's shameful, really.
* Create installer with rails-app-installer
* Create iclassify and icagent rubygems
* Create puppet recipies to install iclassify and icagent
* Internals documentation
* Document using IClassify::client from within puppet templates
-* Add copious amounts of spinner.gif during ajax calls.
* Document building icagent recipies
* Allow icsearch to suppress UUID output
* Allow for different changetypes on calls to /nodes (merge, replace) API
* Allow for calls to specific attribs and tags via the API
-* Support for getting node by hostname
- (eg. usefullt for wget http://somedomain.com:3000/nodes/mynode)
View
4 app/controllers/application.rb
@@ -21,6 +21,8 @@
class ApplicationController < ActionController::Base
# Pick a unique cookie name to distinguish our session data from others'
session :session_key => '_iclassify_session_id'
+
+ include AuthenticatedSystem
def populate_tags_and_attribs(params=nil)
tags = Array.new
@@ -37,4 +39,6 @@ def populate_tags_and_attribs(params=nil)
logger.debug("Attribs: #{attribs.to_yaml}")
return tags, attribs
end
+
+
end
View
16 app/controllers/attribs_controller.rb
@@ -17,6 +17,10 @@
class AttribsController < ApplicationController
+ include AuthorizedAsUser
+
+ before_filter :login_required
+ before_filter :can_write, :except => [ "index", "show" ]
before_filter :find_node
# GET /nodes/:node_id/attribs/new
@@ -40,13 +44,14 @@ def create
@attrib = Attrib.new(params[:attrib])
if (@node.attribs << @attrib)
+ @node.solr_save
flash[:attribute_notice] = "Added attribute #{@attrib.name}"
if request.xhr?
render :partial => "/nodes/attrib_list", :locals => {
:node => @node
}
else
- redirect_to(node_url(@node))
+ redirect_to(node_path(@node))
end
else
render :action => :new
@@ -58,7 +63,8 @@ def create
def update
@attrib = @node.attribs.find(params[:id])
if @attrib.update_attributes(params[:attrib])
- redirect_to node_url(@node)
+ @attrib.update_solr
+ redirect_to node_path(@node)
else
render :action => :edit
end
@@ -68,18 +74,20 @@ def update
# DELETE /nodes/:node_id/attribs/1.xml
def destroy
@attrib = @node.attribs.find(params[:id]).destroy
+ @node.solr_save
flash[:attribute_notice] = "Removed attribute #{@attrib.name}"
if request.xhr?
render :partial => "/nodes/attrib_list", :locals => { :node => @node }
else
- redirect_to node_url(@node) unless request.xhr?
+ redirect_to node_path(@node) unless request.xhr?
end
end
private
def find_node
@node_id = params[:node_id]
- redirect_to nodes_url unless @node_id
+ redirect_to nodes_path unless @node_id
@node = Node.find(@node_id)
+ @node.from_user = true
end
end
View
20 app/controllers/avalues_controller.rb
@@ -17,7 +17,11 @@
class AvaluesController < ApplicationController
- before_filter :find_attrib
+ include AuthorizedAsUser
+
+ before_filter :login_required
+ before_filter :can_write, :except => [ "index", "show" ]
+ before_filter :find_attrib
# GET /nodes/:node_id/attribs/new
def new
@@ -39,11 +43,12 @@ def create
@avalue = Avalue.new(params[:avalue])
if (@attrib.avalues << @avalue)
+ @avalue.update_solr
flash["attrib_edit_#{@attrib.id}_notice".to_sym] = "Added a value"
if request.xhr?
render :partial => "nodes/attrib", :locals => { :attrib => @attrib }
else
- redirect_to node_url(@node)
+ redirect_to node_path(@node)
end
else
render :action => :new
@@ -54,11 +59,12 @@ def create
def update
@avalue = @attrib.avalues.find(params[:id])
if @avalue.update_attributes(params[:avalue])
+ @avalue.update_solr
flash["attrib_edit_#{@attrib.id}_notice".to_sym] = "Changed a value"
if request.xhr?
render :partial => "nodes/attrib", :locals => { :attrib => @attrib }
else
- redirect_to node_url(@node)
+ redirect_to node_path(@node)
end
else
render :action => :edit
@@ -68,21 +74,23 @@ def update
# DELETE /nodes/:node_id/attribs/1
def destroy
@attrib.avalues.find(params[:id]).destroy
+ @node.solr_save
flash["attrib_edit_#{@attrib.id}_notice".to_sym] = "Removed a value."
if request.xhr?
render :partial => "nodes/attrib", :locals => { :attrib => @attrib }
else
- redirect_to node_url(@node)
+ redirect_to node_path(@node)
end
end
private
def find_attrib
@node_id = params[:node_id]
- redirect_to nodes_url unless @node_id
+ redirect_to nodes_path unless @node_id
@node = Node.find(@node_id)
+ @node.from_user = true
@attrib_id = params[:attrib_id]
- redirect_to attribs_url unless @attrib_id
+ redirect_to node_attribs_path unless @attrib_id
@attrib = @node.attribs.find(@attrib_id)
end
end
View
10 app/controllers/dashboard_controller.rb
@@ -17,6 +17,12 @@
class DashboardController < ApplicationController
+ include AuthorizedAsUser
+
+ before_filter :login_required
+ before_filter :can_write, :except => [ "index" ]
+
+
# GET /
# GET /dashboard
# GET /dashboard.xml
@@ -31,7 +37,7 @@ def bulk_tag
if params[:tag_nodes] && params[:tag_list]
tag_nodes = params[:tag_nodes]
tags = Tag.create_missing_tags(params[:tag_list].split(" "))
- Node.bulk_tag(tag_nodes, tags)
+ Node.bulk_tag(tag_nodes, tags, true)
flash[:bulk_tags_notice] = "Nodes have been updated."
redirect_to(url_for(:controller => "dashboard", :action => "index")) unless request.xhr?
@tags = Tag.find(:all)
@@ -63,7 +69,7 @@ def bulk_tag
private
def get_unclassified_nodes
- uctag = Tag.find_by_name("unclassified")
+ uctag = Tag.find_by_name("unclassified", :include => :nodes)
uctag ? uctag.nodes : Array.new
end
end
View
17 app/controllers/nodes_controller.rb
@@ -16,6 +16,11 @@
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
class NodesController < ApplicationController
+ include AuthorizedAsUser
+
+ before_filter :login_required
+ before_filter :can_write, :except => [ "index", "show", "autocomplete" ]
+
# GET /nodes
def index
@nodes = Node.find(:all)
@@ -41,11 +46,10 @@ def edit
def create
tags, attribs = populate_tags_and_attribs(params)
@node = Node.new(params[:node])
-
respond_to do |format|
if @node.save_with_tags_and_attribs(tags, attribs)
flash[:notice] = 'Node was successfully created.'
- redirect_to node_url(@node)
+ redirect_to node_path(@node)
else
render :action => "new"
end
@@ -55,18 +59,19 @@ def create
# PUT /nodes/1
def update
@node = Node.find(params[:id])
+ @node.from_user = true
if params[:node].has_key?(:tags) && params[:node].has_key?(:attribs)
tags, attribs = populate_tags_and_attribs(params)
if @node.update_with_tags_and_attribs(params[:node], tags, attribs)
flash[:notice] = 'Node was successfully updated.'
- redirect_to node_url(@node)
+ redirect_to node_path(@node)
else
render :action => "edit"
end
else
if @node.update_attributes(params[:node])
flash[:notice] = 'Node was successfully updated.'
- redirect_to node_url(@node)
+ redirect_to node_path(@node)
else
render :action => "edit"
end
@@ -77,13 +82,13 @@ def update
def destroy
@node = Node.find(params[:id])
@node.destroy
- redirect_to nodes_url
+ redirect_to nodes_path
end
def show_uuid
@node = Node.find_by_uuid(params[:uuid])
raise "Cannot find node" unless @node
- redirect_to node_url(@node)
+ redirect_to node_path(@node)
end
def update_uuid
View
1 app/controllers/options_controller.rb
@@ -16,6 +16,7 @@
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
class OptionsController < ApplicationController
+ session :disabled => true
def options
render :text => "OK"
View
76 app/controllers/rest_nodes_controller.rb
@@ -16,12 +16,14 @@
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
class RestNodesController < ApplicationController
+ include AuthorizedAsUser
+ before_filter :login_required, :only => [ :index, :destroy ]
- session :disabled => true
+# session :disabled => true
# GET /rest/nodes.xml
def index
- @nodes = Node.find(:all)
+ @nodes = Node.find(:all, :include => [ :tags, :attribs ])
respond_to do |format|
format.xml { render :layout => false }
@@ -31,20 +33,29 @@ def index
# GET /rest/nodes/1.xml
def show
@node, @node_unique_field = Node.find_by_unique(params[:id])
-
- respond_to do |format|
- format.xml { render :layout => false, :template => "rest_nodes/show.rxml" }
+ if check_node_or_user?(@node)
+ respond_to do |format|
+ format.xml { render :layout => false, :template => "rest_nodes/show.rxml" }
+ end
+ else
+ if @node
+ headers["Status"] = "Unauthorized"
+ render :text => "You are neither a user or UUID #{params[:id]}", :status => '401 Unauthorized'
+ else
+ headers["Status"] = "Not Found"
+ render :text => "Cannot find Node with #{params[:id]}", :status => '404 Not Found'
+ end
end
end
# POST /rest/nodes.xml
def create
tags, attribs = populate_tags_and_attribs(params)
@node = Node.new(params[:node])
-
+ @node.quarantined = true unless authorized?
respond_to do |format|
if @node.save_with_tags_and_attribs(tags, attribs)
- format.xml { head :created, :location => node_url(@node) }
+ format.xml { head :created, :location => node_path(@node) }
else
format.xml { render :xml => @node.errors.to_xml }
end
@@ -54,33 +65,52 @@ def create
# PUT /rest/nodes/1.xml
def update
@node, @node_unique_field = Node.find_by_unique(params[:id])
-
- respond_to do |format|
- if params[:node].has_key?(:tags) && params[:node].has_key?(:attribs)
- tags, attribs = populate_tags_and_attribs(params)
- if @node.update_with_tags_and_attribs(params[:node], tags, attribs)
- format.xml { head :ok }
+ if check_node_or_user?(@node)
+ # You can't take yourself out of quarantine with a parameter
+ params[:node].delete(:quarantined) if params[:node].has_key?(:quarantined)
+ @node.from_user = true if authorized?
+ respond_to do |format|
+ if params[:node].has_key?(:tags) && params[:node].has_key?(:attribs)
+ tags, attribs = populate_tags_and_attribs(params)
+ if @node.update_with_tags_and_attribs(params[:node], tags, attribs)
+ format.xml { head :ok }
+ else
+ format.xml { render :xml => @node.errors.to_xml }
+ end
else
- format.xml { render :xml => @node.errors.to_xml }
- end
- else
- if @node.update_attributes(params[:node])
- format.xml { head :ok }
- else
- format.xml { render :xml => @node.errors.to_xml }
+ if @node.update_attributes(params[:node])
+ format.xml { head :ok }
+ else
+ format.xml { render :xml => @node.errors.to_xml }
+ end
end
end
+ else
+ headers["Status"] = "Unauthorized"
+ render :text => "You are neither a user or UUID #{params[:node][:uuid]}", :status => '401 Unauthorized'
end
end
# DELETE /rest/nodes/1.xml
def destroy
@node, node_unique_field = Node.find_by_unique(params[:id])
- @node.destroy
+ if check_node_or_user?(@node)
+ @node.destroy
- respond_to do |format|
- format.xml { head :ok }
+ respond_to do |format|
+ format.xml { head :ok }
+ end
+ else
+ headers["Status"] = "Unauthorized"
+ render :text => "You are neither a user or UUID #{params[:id]}", :status => '401 Unauthorized'
end
end
+ protected
+ def check_node_or_user?(tocheck)
+ return true if current_user.is_a?(User) && current_user.readwrite == true
+ return true if current_user.is_a?(Node) && current_user.id == tocheck.id
+ return false
+ end
+
end
View
5 app/controllers/rest_search_controller.rb
@@ -1,5 +1,8 @@
class RestSearchController < ApplicationController
- session :disabled => true
+ include AuthorizedAsUser
+
+ # session :disabled => true
+ before_filter :login_required
def index
@nodes = Node.find_record_by_solr(params[:q]) if params[:q]
View
5 app/controllers/rest_tags_controller.rb
@@ -16,8 +16,9 @@
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
class RestTagsController < ApplicationController
-
- session :disabled => true
+ include AuthorizedAsUser
+ before_filter :login_required
+# session :disabled => true
# GET /rest/tags.xml
def index
View
3 app/controllers/search_controller.rb
@@ -16,6 +16,9 @@
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
class SearchController < ApplicationController
+ include AuthorizedAsUser
+ before_filter :login_required
+
def index
@nodes = Node.find_record_by_solr(params[:q]) if params[:q]
@nodes ||= Array.new
View
37 app/controllers/sessions_controller.rb
@@ -0,0 +1,37 @@
+# This controller handles the login/logout function of the site.
+class SessionsController < ApplicationController
+ # Be sure to include AuthenticationSystem in Application Controller instead
+ include AuthenticatedSystem
+ include AuthorizedAsUser
+
+ # render new.rhtml
+ def new
+ end
+
+ def create
+ if params[:login] != UUIDREGEX
+ self.current_user = User.authenticate(params[:login], params[:password])
+ else
+ logger.info("Attempt to log in to the web interface with a Node UUID (#{params[:login]})!")
+ self.current_user = nil
+ end
+ if logged_in?
+ if params[:remember_me] == "1"
+ self.current_user.remember_me
+ cookies[:auth_token] = { :value => self.current_user.remember_token , :expires => self.current_user.remember_token_expires_at }
+ end
+ redirect_back_or_default('/')
+ flash[:notice] = "Logged in successfully"
+ else
+ render :action => 'new'
+ end
+ end
+
+ def destroy
+ self.current_user.forget_me if logged_in?
+ cookies.delete :auth_token
+ reset_session
+ flash[:notice] = "You have been logged out."
+ redirect_back_or_default('/')
+ end
+end
View
17 app/controllers/tags_controller.rb
@@ -16,8 +16,10 @@
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
class TagsController < ApplicationController
+ include AuthorizedAsUser
before_filter :find_node
+ before_filter :can_write, :except => [ "index", "show", "all_index", "all_show" ]
# GET /nodes/:node_id/tags/new
def new
@@ -79,7 +81,7 @@ def create
result = @node.save
end
if result
- redirect_to node_url(@node)
+ redirect_to node_path(@node)
else
render :action => :new
end
@@ -112,7 +114,8 @@ def all_create
def update
@tag = @node.tags.find(params[:id])
if @tag.update_attributes(params[:tag])
- redirect_to node_url(@node)
+ @node.solr_save
+ redirect_to node_path(@node)
else
render :action => :edit
end
@@ -124,6 +127,7 @@ def all_update
@tag = Tag.find(params[:id])
@tagged_nodes = get_tagged_nodes()
if @tag.update_attributes(params[:tag])
+ @tag.update_solr
redirect_to url_for(:controller => "tags", :action => "all_show", :id => @tag.id)
else
render :action => :all_edit
@@ -134,13 +138,15 @@ def all_update
# DELETE /nodes/:node_id/tags/1.xml
def destroy
@node.tags.delete(@node.tags.find(params[:id]))
- redirect_to node_url(@node)
+ @node.solr_save
+ redirect_to node_path(@node)
end
# DELETE /tags/:tag_id
# DELETE /tags/:tag_id.xml
def all_destroy
- Tag.find(params[:id]).destroy
+ dtag = Tag.find(params[:id]).destroy
+ dtag.update_solr
if request.xhr?
render(:partial => "/tags/tag_listing")
else
@@ -193,8 +199,9 @@ def all_node_add
def find_node
if params[:node_id]
@node_id = params[:node_id]
- redirect_to nodes_url unless @node_id
+ redirect_to nodes_path unless @node_id
@node = Node.find(@node_id)
+ @node.from_user = true
end
end
View
51 app/controllers/users_controller.rb
@@ -0,0 +1,51 @@
+class UsersController < ApplicationController
+ # Be sure to include AuthenticationSystem in Application Controller instead
+ include AuthenticatedSystem
+ include AuthorizedAsUser
+
+ before_filter :login_required
+
+ # render new.rhtml
+ def new
+ end
+
+ def index
+ @users = User.find(:all)
+ end
+
+ def create
+ @user = User.new(params[:user])
+ @user.save!
+ redirect_back_or_default('/')
+ flash[:notice] = "Added user #{@user.login}"
+ rescue ActiveRecord::RecordInvalid
+ render :action => 'new'
+ end
+
+ def edit
+ @user = User.find_by_id(params[:id])
+ end
+
+ def update
+ @user = User.find_by_id(params[:id])
+ if @user.update_attributes(params[:user])
+ flash[:notice] = "User Updated"
+ redirect_to users_path
+ else
+ render :action => :edit
+ end
+ end
+
+ def destroy
+ @user = User.find(params[:id])
+ flash[:notice] = "User Deleted"
+ @user.destroy
+ if @user.id == current_user.id
+ self.current_user.forget_me if logged_in?
+ cookies.delete :auth_token
+ reset_session
+ end
+ redirect_to users_path
+ end
+
+end
View
2 app/helpers/sessions_helper.rb
@@ -0,0 +1,2 @@
+module SessionsHelper
+end
View
2 app/helpers/users_helper.rb
@@ -0,0 +1,2 @@
+module UsersHelper
+end
View
19 app/models/attrib.rb
@@ -16,16 +16,17 @@
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
class Attrib < ActiveRecord::Base
+
belongs_to :node
has_many :avalues, :dependent => :destroy
validates_presence_of :name, :message => "Must have a name"
- after_create :update_solr
- after_update :update_solr
- after_destroy :update_solr
- after_save :update_solr
-
+ # after_create :update_solr
+ # after_update :update_solr
+ # after_destroy :update_solr
+ # after_save :update_solr
+
def self.get_all_names
find(:all, :select => "name", :group => "name").collect { |a| a.name }
end
@@ -35,7 +36,7 @@ def self.create_missing_attribs(node, attribs, options=Hash.new)
attribs.each do |attrib_hash|
attrib = nil
if node.id
- attrib = Attrib.find(:first, :conditions => [ "node_id = ? and name = ?", node.id, attrib_hash['name'] ])
+ attrib = Attrib.find(:first, :conditions => [ "node_id = ? and name = ?", node.id, attrib_hash['name'] ], :include => :avalues)
unless attrib
attrib = node.attribs.new(
:name => attrib_hash['name']
@@ -51,21 +52,17 @@ def self.create_missing_attribs(node, attribs, options=Hash.new)
attrib.avalues << attrib.avalues.new(:value => v)
end
end
- logger.debug("Attrib dump: #{attrib.to_yaml}")
if options.has_key?(:delete) && options[:delete]
- logger.debug("Deleting values that should not be")
attrib.avalues.each do |av|
- logger.debug("Deleting value #{av.value} unless #{attrib_hash['values']['value'].include?(av.value)}")
av.destroy unless attrib_hash['values']['value'].include?(av.value)
end
end
- logger.debug(" #{attrib.to_yaml}")
attrib_array << attrib
end
attrib_array
end
def update_solr
- node.solr_save
+ node.solr_save
end
end
View
12 app/models/avalue.rb
@@ -20,12 +20,14 @@ class Avalue < ActiveRecord::Base
validates_presence_of :value, :message => "You must have a value!"
- after_create :update_solr
- after_update :update_solr
- after_destroy :update_solr
- after_save :update_solr
+ # after_create :update_solr
+ # after_update :update_solr
+ # after_destroy :update_solr
+ # after_save :update_solr
+
+ attr_accessor :bulk_load
def update_solr
- attrib.node.solr_save
+ attrib.node.solr_save unless self.bulk_load == true
end
end
View
136 app/models/node.rb
@@ -16,59 +16,80 @@
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
class Node < ActiveRecord::Base
+
+ include PasswordEncryption
+
UUID_REGEX = /^[[:xdigit:]]{8}[:-][[:xdigit:]]{4}[:-][[:xdigit:]]{4}[:-][[:xdigit:]]{4}[:-][[:xdigit:]]{12}$/
+ attr_accessor :password
+ attr_accessor :skip_solr
+ attr_accessor :from_user
+
has_many :attribs, :dependent => :destroy
has_and_belongs_to_many :tags
- validates_presence_of :uuid
+ validates_presence_of :password, :if => :password_required?
+ validates_presence_of :uuid
validates_uniqueness_of :uuid
validates_format_of :uuid,
:with => UUID_REGEX,
:message => "Must be a valid UUID"
+ before_save :encrypt_password
+ before_save :update_quarantined
+
# acts_as_ferret(:fields => [ :uuid, :notes, :description, :tag ], :remote => true )
acts_as_solr(:fields => [ {:uuid => :text}, {:notes => :text}, {:description => :text}, {:tag => :text} ],
:auto_commit => true)
+ def self.authenticate(username, password)
+ node = find_by_uuid(username) # need to get the salt
+ node && node.authenticated?(password) ? node : nil
+ end
+
def self.find_record_by_solr(q)
ids = find_id_by_solr(q, :limit => :all)
if ids.total > 0
- logger.debug(ids.to_yaml)
find_by_sql("SELECT id, uuid, description, notes FROM nodes WHERE id IN (#{ids.docs.join(', ')}) ORDER BY description")
else
- logger.debug("returning nothing")
+ logger.debug("Returning nothing")
Array.new
end
end
# saves to the Solr index
def solr_save
- return true unless configuration[:if]
- if evaluate_condition(configuration[:if], self)
- logger.debug "solr_save: #{self.class.name} : #{record_id(self)}"
- this_doc = to_solr_doc
- field_type = configuration[:facets] && configuration[:facets].include?(field) ? :facet : :text
- field_boost= solr_configuration[:default_boost]
- suffix = get_solr_field_type(field_type)
- attribs.each do |attrib|
- if attrib.name != "id"
- attrib.avalues.collect { |av| av.value }.each do |v|
- v = set_value_if_nil(suffix) if v.to_s == ""
- logger.debug("adding field #{attrib.name}_#{suffix}: #{v.to_s}")
- field = Solr::Field.new("#{attrib.name}_#{suffix}" => ERB::Util.html_escape(v.to_s))
- this_doc << field
+ if self.skip_solr == true
+ logger.debug("Skipping solr_save")
+ else
+ if self.quarantined == false
+ return true unless configuration[:if]
+ if evaluate_condition(configuration[:if], self)
+ logger.debug "solr_save: #{self.class.name} : #{record_id(self)}"
+ this_doc = to_solr_doc
+ field_type = configuration[:facets] && configuration[:facets].include?(field) ? :facet : :text
+ field_boost= solr_configuration[:default_boost]
+ suffix = get_solr_field_type(field_type)
+ attribs(:include => :avalues).each do |attrib|
+ if attrib.name != "id"
+ attrib.avalues.collect { |av| av.value }.each do |v|
+ v = set_value_if_nil(suffix) if v.to_s == ""
+ logger.debug("adding field #{attrib.name}_#{suffix}: #{v.to_s}")
+ field = Solr::Field.new("#{attrib.name}_#{suffix}" => ERB::Util.html_escape(v.to_s))
+ this_doc << field
+ end
+ end
end
+ logger.debug(this_doc.to_xml)
+ solr_add(this_doc)
+ solr_commit if configuration[:auto_commit]
+ true
+ else
+ solr_destroy
end
end
- logger.debug(this_doc.to_xml)
- solr_add(this_doc)
- solr_commit if configuration[:auto_commit]
- true
- else
- solr_destroy
end
end
@@ -104,9 +125,10 @@ def self.find_by_unique(unique)
return node, node_unique_field
end
- def self.bulk_tag(node_hash, tags)
+ def self.bulk_tag(node_hash, tags, from_user=false)
node_hash.each do |node_id, value|
node = find(node_id.to_i)
+ node.from_user = true if from_user
node.tags = tags
node.save
end
@@ -145,60 +167,19 @@ def update_with_tags_and_attribs(params, tag_array=nil, attrib_array=nil)
self.tags = Tag.create_missing_tags(tag_array)
end
if attrib_array
- attribs.each do |attrib|
+ attribs(:include => :avalues).each do |attrib|
attribs.delete(attrib) unless attrib_array.include?({'name' => attrib.name })
end
self.attribs = Attrib.create_missing_attribs(self, attrib_array, { :delete => true })
end
self.save
end
- # def parse_query(query=nil, options={}, models=nil)
- # valid_options = [:offset, :limit, :facets, :models, :results_format, :order, :scores, :operator]
- # query_options = {}
- # return if query.nil?
- # raise "Invalid parameters: #{(options.keys - valid_options).join(',')}" unless (options.keys - valid_options).empty?
- # begin
- # Deprecation.validate_query(options)
- # query_options[:start] = options[:offset]
- # query_options[:rows] = options[:limit]
- # query_options[:operator] = options[:operator]
- #
- # # first steps on the facet parameter processing
- # if options[:facets]
- # query_options[:facets] = {}
- # query_options[:facets][:limit] = -1 # TODO: make this configurable
- # query_options[:facets][:sort] = :count if options[:facets][:sort]
- # query_options[:facets][:mincount] = 0
- # query_options[:facets][:mincount] = 1 if options[:facets][:zeros] == false
- # query_options[:facets][:fields] = options[:facets][:fields].collect{|k| "#{k}_facet"} if options[:facets][:fields]
- # query_options[:filter_queries] = replace_types(options[:facets][:browse].collect{|k| "#{k.sub!(/ *: */,"_facet:")}"}) if options[:facets][:browse]
- # query_options[:facets][:queries] = replace_types(options[:facets][:query].collect{|k| "#{k.sub!(/ *: */,"_t:")}"}) if options[:facets][:query]
- # end
- #
- # if models.nil?
- # # TODO: use a filter query for type, allowing Solr to cache it individually
- # models = "AND #{solr_configuration[:type_field]}:#{self.name}"
- # field_list = solr_configuration[:primary_key_field]
- # else
- # field_list = "id"
- # end
- #
- # query_options[:field_list] = [field_list, 'score']
- # query = "(#{query.gsub(/ *: */,"_t:")}) #{models}"
- # order = options[:order].split(/\s*,\s*/).collect{|e| e.gsub(/\s+/,'_t ').gsub(/\bscore_t\b/, 'score') }.join(',') if options[:order]
- # query_options[:query] = replace_types([query])[0] # TODO adjust replace_types to work with String or Array
- #
- # if options[:order]
- # # TODO: set the sort parameter instead of the old ;order. style.
- # query_options[:query] << ';' << replace_types([order], false)[0]
- # end
- #
- # ActsAsSolr::Post.execute(Solr::Request::Standard.new(query_options))
- # rescue
- # raise "There was a problem executing your search: #{$!}"
- # end
- # end
+ def encrypt_password
+ return if password.blank?
+ self.salt = Digest::SHA1.hexdigest("--#{Time.now.to_s}--#{uuid}--") if new_record?
+ self.crypted_password = encrypt(password)
+ end
# Serializes all the nodes in the database
def self.rest_serialize_all
@@ -230,7 +211,18 @@ def rest_serialize
ahash[:values] = attrib.avalues.collect{ |av| av.value }
rest_hash[:attribs] << ahash
end
- logger.debug("Rest: #{rest_hash.to_yaml}")
rest_hash
end
+
+ protected
+ def update_quarantined
+ if from_user == true && quarantined == true
+ logger.debug("Turning off quarantine!")
+ self.quarantined = false
+ self.save
+ else
+ logger.error("from_user is #{from_user} and quarantined is #{quarantined}")
+ end
+ end
+
end
View
12 app/models/tag.rb
@@ -15,22 +15,22 @@
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
-class Tag < ActiveRecord::Base
+class Tag < ActiveRecord::Base
has_and_belongs_to_many :nodes
validates_presence_of :name
validates_uniqueness_of :name
validates_format_of :name,
:with => /\A(\w|\-)+\Z/,
:message => "Name must be alphanumeric plus _ and -."
- after_create :update_solr
- after_update :update_solr
- after_destroy :update_solr
- after_save :update_solr
+ # after_create :update_solr
+ # after_update :update_solr
+ # after_destroy :update_solr
+ # after_save :update_solr
def update_solr
nodes.each do |node|
- node.solr_save
+ node.solr_save
end
end
View
26 app/models/user.rb
@@ -0,0 +1,26 @@
+class User < ActiveRecord::Base
+
+ include PasswordEncryption
+
+ # Virtual attribute for the unencrypted password
+ attr_accessor :password
+
+ validates_presence_of :login
+ validates_presence_of :password, :if => :password_required?
+ validates_presence_of :password_confirmation, :if => :password_required?
+ validates_length_of :password, :within => 4..40, :if => :password_required?
+ validates_confirmation_of :password, :if => :password_required?
+ validates_length_of :login, :within => 3..40
+ validates_uniqueness_of :login, :case_sensitive => false
+ before_save :encrypt_password
+
+ # prevents a user from submitting a crafted form that bypasses activation
+ # anything else you want your user to change should be added here.
+ attr_accessible :login, :password, :password_confirmation, :readwrite
+
+ # Authenticates a user by their login name and unencrypted password. Returns the user or nil.
+ def self.authenticate(login, password)
+ u = find_by_login(login) # need to get the salt
+ u && u.authenticated?(password) ? u : nil
+ end
+end
View
4 app/views/attribs/edit.rhtml
@@ -4,10 +4,10 @@
<% @attrib.avalues.each do |avalue| %>
<%= error_messages_for :avalue %>
-<% form_for :avalue, avalue, :url => avalue_url(:node_id => @node.id, :attrib_id => @attrib.id, :id => avalue.id), :html => { :method => 'put' } do |form| %>
+<% form_for :avalue, avalue, :url => node_attrib_avalue_path(:node_id => @node.id, :attrib_id => @attrib.id, :id => avalue.id), :html => { :method => 'put' } do |form| %>
<%= render :partial => 'avalues/form', :locals => { :attrib => @attrib, :node => @node, :form => form } %>
<%= submit_tag "Update" %>
-<%= link_to 'Remove', avalue_url(:node_id => @node.id, :attrib_id => @attrib.id, :id => avalue.id), :confirm => 'Are you sure?', :method => :delete %>
+<%= link_to 'Remove', node_attrib_avalue_path(:node_id => @node.id, :attrib_id => @attrib.id, :id => avalue.id), :confirm => 'Are you sure?', :method => :delete %>
<% end %>
<% end %>
View
2 app/views/attribs/new.rhtml
@@ -1,7 +1,7 @@
<fieldset>
<legend>Add an Attribute</legend>
<%= error_messages_for :attrib %>
-<% form_for :attrib, :url => attribs_url(:node_id => @node.id) do |form| %>
+<% form_for :attrib, :url => node_attribs_path(:node_id => @node.id) do |form| %>
<%= render :partial => 'form', :locals => { :node => @node, :form => form } %>
<%= submit_tag "Add Attribute" %>
View
4 app/views/avalues/edit.rhtml
@@ -1,9 +1,9 @@
<fieldset>
<legend>Edit Value</legend>
<%= error_messages_for :avalue %>
-<% form_for :avalue, :url => avalue_url(:node_id => @node.id, :attrib_id => @attrib.id), :html => { :method => 'put' } do |form| %>
+<% form_for :avalue, :url => node_attrib_avalue_path(:node_id => @node.id, :attrib_id => @attrib.id), :html => { :method => 'put' } do |form| %>
<%= render :partial => 'form', :locals => { :attrib => @attrib, :node => @node, :form => form } %>
<%= submit_tag "Update" %>
-<%= link_to 'Remove', avalue_url(:node_id => @node.id, :attrib_id => @attrib.id, :id => avalue.id), :confirm => 'Are you sure?', :method => :delete %>
+<%= link_to 'Remove', node_attrib_avalue_path(:node_id => @node.id, :attrib_id => @attrib.id, :id => avalue.id), :confirm => 'Are you sure?', :method => :delete %>
<% end %>
</fieldset>
View
2 app/views/avalues/new.rhtml
@@ -1,7 +1,7 @@
<fieldset>
<legend>Add Value</legend>
<%= error_messages_for :avalue %>
-<% form_for :avalue, :url => avalues_url(:node_id => @node.id, :attrib_id => @attrib.id), :html => { :method => 'post' } do |form| %>
+<% form_for :avalue, :url => node_attrib_avalues_path(:node_id => @node.id, :attrib_id => @attrib.id), :html => { :method => 'post' } do |form| %>
<%= render :partial => 'form', :locals => { :attrib => @attrib, :node => @node, :form => form } %>
<%= submit_tag "Create" %>
<% end %>
View
3 app/views/dashboard/index.rhtml
@@ -1,7 +1,8 @@
+<% if current_user.readwrite == true -%>
<div class="section_box">
<%= render(:partial => "search/bulk_tag", :locals => { :heading => "Unclassified Nodes", :nodes => @unclassified_nodes, :tags => @tags }) %>
-
</div>
+<% end -%>
<div class="section_box">
<h1>All Nodes</h1>
<%= render :partial => "nodes/listing", :locals => { :table_id => "all_nodes_list", :checkbox => false, :nodes => @all_nodes.sort { |a,b| a.description <=> b.description } }%>
View
1 app/views/layouts/_footer.rhtml
@@ -1,2 +1,3 @@
+<div id="footer"></div>
</body>
</html>
View
9 app/views/layouts/_header.rhtml
@@ -22,8 +22,15 @@
<h1><%= link_to 'iClassify', url_for(:controller => 'dashboard', :action => 'index') %></h1>
</div>
<div id="search">
- <%= link_to 'List Nodes', nodes_path %> |
+ Hello
+ <% if current_user.readwrite -%>
+ <%= link_to(current_user.login, edit_user_path(current_user.id)) %> (<%= link_to('Logout', session_path, :method => :delete)%>)
+ |
+ <%= link_to('User List', users_path)%> |
<%= link_to 'Create a new node', new_node_path %>
+ <% else -%>
+ <%= current_user.login %> (<%= link_to('Logout', session_path, :method => :delete) %>)
+ <% end -%>
<%= render :partial => "search/search_form" %>
</div>
</div>
View
2 app/views/layouts/_minimal_footer.rhtml
@@ -0,0 +1,2 @@
+</body>
+</html>
View
27 app/views/layouts/_minimal_header.rhtml
@@ -0,0 +1,27 @@
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+
+<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
+<head>
+ <meta http-equiv="content-type" content="text/html;charset=UTF-8" />
+ <title>iClassify</title>
+ <%= stylesheet_link_tag 'iclassify' %>
+ <%= stylesheet_link_tag 'tablesorter' %>
+ <%= javascript_include_tag "jquery-1.2.1.pack.js" %>
+ <%= javascript_include_tag "autocomplete.js" %>
+ <%= javascript_include_tag "jquery.form.js" %>
+ <%= javascript_include_tag "jquery.livequery.min.js" %>
+ <%= javascript_include_tag "jquery.tablesorter.pack.js" %>
+ <%= javascript_include_tag "jquery.tablesorter.pager.js" %>
+ <%= javascript_include_tag "jquery.dimensions.pack.js"%>
+ <%= javascript_include_tag "iclassify.js" %>
+</head>
+<body>
+<div id="header">
+ <div id="logo">
+ <h1><%= link_to 'iClassify', url_for(:controller => 'dashboard', :action => 'index') %></h1>
+ </div>
+</div>
+
+
+
View
6 app/views/layouts/sessions.rhtml
@@ -0,0 +1,6 @@
+<%= render :partial => "layouts/minimal_header" %>
+<div id="content">
+<p style="color: green"><%= flash[:notice] %></p>
+<%= yield %>
+</div>
+<%= render :partial => "layouts/minimal_footer" %>
View
6 app/views/layouts/users.rhtml
@@ -0,0 +1,6 @@
+<%= render :partial => "layouts/header" %>
+<div id="content">
+<p style="color: green"><%= flash[:notice] %></p>
+<%= yield %>
+</div>
+<%= render :partial => "layouts/footer" %>
View
8 app/views/nodes/_attrib.rhtml
@@ -1,20 +1,20 @@
<h2 class="inline">Edit Attribute '<%= h attrib.name %>'</h2>
- <%= remove_button_remote("remove_button_attrib_#{attrib.id}", "Remove Attribute", attrib_url(:node_id => @node.id, :id => attrib.id), "attributes_list", "Really delete attribute #{h attrib.name}?") %>
+ <%= remove_button_remote("remove_button_attrib_#{attrib.id}", "Remove Attribute", node_attrib_path(:node_id => @node.id, :id => attrib.id), "attributes_list", "Really delete attribute #{h attrib.name}?") %>
<p style="color: green" id="attrib_edit_<%= attrib.id %>_notice"><%= flash["attrib_edit_#{attrib.id}_notice".to_sym] %></p>
<%= error_messages_for :attrib %>
<% attrib.avalues.each do |avalue| %>
<%= error_messages_for :avalue %>
- <% form_for :avalue, avalue, :url => avalue_url(:node_id => @node.id, :attrib_id => attrib.id, :id => avalue.id), :html => { :class => "remote_form inline", :id => "edit_avalue_#{avalue.id}", :method => 'put', :update => "attrib_edit_#{attrib.id}" } do |form| %>
+ <% form_for :avalue, avalue, :url => node_attrib_avalue_path(:node_id => @node.id, :attrib_id => attrib.id, :id => avalue.id), :html => { :class => "remote_form inline", :id => "edit_avalue_#{avalue.id}", :method => 'put', :update => "attrib_edit_#{attrib.id}" } do |form| %>
<%= render :partial => 'avalues/form', :locals => { :attrib => attrib, :node => @node, :form => form } %>
<%= submit_tag "Update" %>
<% end %>
- <%= remove_button_remote("remove_button_avalue_#{avalue.id}", "Remove Value", avalue_url(:node_id => @node.id, :attrib_id => attrib.id, :id => avalue.id), "attrib_edit_#{attrib.id}", "Really delete #{h attrib.name} value #{h avalue.value}")%>
+ <%= remove_button_remote("remove_button_avalue_#{avalue.id}", "Remove Value", node_attrib_avalue_path(:node_id => @node.id, :attrib_id => attrib.id, :id => avalue.id), "attrib_edit_#{attrib.id}", "Really delete #{h attrib.name} value #{h avalue.value}")%>
<% end %>
<h3>Add Value</h3>
<%= error_messages_for :avalue %>
-<% form_for :avalue, attrib.avalues.new, :url => avalues_url(:node_id => @node.id, :attrib_id => attrib.id), :html => { :id => "new_avalue_#{h attrib.id}", :class => "remote_form", :method => 'post', :update => "attrib_edit_#{attrib.id}" } do |form| %>
+<% form_for :avalue, attrib.avalues.new, :url => node_attrib_avalues_path(:node_id => @node.id, :attrib_id => attrib.id), :html => { :id => "new_avalue_#{h attrib.id}", :class => "remote_form", :method => 'post', :update => "attrib_edit_#{attrib.id}" } do |form| %>
<%= render :partial => 'avalues/form', :locals => { :attrib => attrib, :node => @node, :form => form } %>
<%= submit_tag "Add" %><%= spinner_tag "new_avalue_#{h attrib.id}_spinner" %>
<% end %>
View
6 app/views/nodes/_listing.rhtml
@@ -7,8 +7,10 @@
<% end %>
<th>Description&nbsp&nbsp&nbsp&nbsp</th>
<th>UUID</th>
+ <% if current_user.readwrite == true -%>
<th>
</th>
+ <% end -%>
</tr>
</thead>
<tbody>
@@ -21,11 +23,13 @@
<% end %>
<td>
<%= link_to("#{h node.description}", node_path(node)) %></td>
- <td><%= h node.uuid %></td>
+ <td class="<%= node.quarantined ? "quarantined" : "" %>"><%= h node.uuid %></td>
+ <% if current_user.readwrite == true -%>
<td>
<%= edit_button("Edit", edit_node_path(node))%>
<%= remove_button("Delete", node_path(node), "Delete node #{h node.description}?")%>
</tr>
+ <% end -%>
<% end -%>
</tbody>
</table>
View
4 app/views/nodes/edit.rhtml
@@ -13,13 +13,13 @@
</div>
<div id="new_tag_data">
- <% form_for :tag, :url => tags_url(:node_id => @node) do |form| %>
+ <% form_for :tag, :url => node_tags_path(:node_id => @node) do |form| %>
<%= render :partial => "/tags/form", :locals => { :node => @node, :current_tags => @node.tags, :tags => Tag.find(:all), :form => form, :legend => "Tags" }%>
<% end %>
</div>
<div id="new_attribute_data" class="fieldset">
- <%= render :partial => "/attribs/form", :locals => { :node => @node, :heading => "Add an Attribute", :url => attribs_url(:node_id => @node) } %>
+ <%= render :partial => "/attribs/form", :locals => { :node => @node, :heading => "Add an Attribute", :url => node_attribs_path(:node_id => @node) } %>
</div>
<div id="attributes_list">
<%= render :partial => "attrib_list", :locals => { :node => @node }%>
View
4 app/views/nodes/show.rhtml
@@ -1,10 +1,10 @@
<div class="section_box">
<h1 class="inline">Node <%= h @node.description %></h1>
-
+<% if current_user.readwrite == true -%>
<%= edit_button("Edit", edit_node_path(@node)) %>
<%= remove_button("Delete", node_path, 'Are you sure?') %>
-
+<% end -%>
<table class="node_display">
<tr class="odd">
<th>UUID</th><td><%= h @node.uuid %></td>
View
4 app/views/rest_nodes/_node.rxml
@@ -1,12 +1,12 @@
xml = xml_instance
-xml.node(:link => rest_node_url(:id => node_unique_field)) do
+xml.node(:link => rest_node_path(:id => node_unique_field)) do
xml.id(node[:id])
xml.uuid(node[:uuid])
xml.description(node[:description])
xml.notes(node[:notes])
xml.tags do
node[:tags].each do |tag|
- xml.tag(tag[:name], :link => rest_tag_url(:id => tag[:id]), :id => tag[:id])
+ xml.tag(tag[:name], :link => rest_tag_path(:id => tag[:id]), :id => tag[:id])
end
end
xml.attribs do
View
4 app/views/rest_tags/_tag.rxml
@@ -1,10 +1,10 @@
xml = xml_instance
-xml.tag(:link => rest_tag_url(:id => tag_unique_field)) do
+xml.tag(:link => rest_tag_path(:id => tag_unique_field)) do
xml.id(tag[:id])
xml.name(tag[:name])
xml.nodes do
tag[:nodes].each do |node|
- xml.node(:link => rest_node_url(:id => node[:id])) do
+ xml.node(:link => rest_node_path(:id => node[:id])) do
xml.id(node[:id])
xml.uuid(node[:uuid])
xml.description(node[:description])
View
14 app/views/sessions/_form.rhtml
@@ -0,0 +1,14 @@
+<% form_tag session_path do -%>
+<p><label for="login">Login</label><br/>
+<%= text_field_tag 'login' %></p>
+
+<p><label for="password">Password</label><br/>
+<%= password_field_tag 'password' %></p>
+
+<!-- Uncomment this if you want this functionality
+<p><label for="remember_me">Remember me:</label>
+<%= check_box_tag 'remember_me' %></p>
+-->
+
+<p><%= submit_tag 'Log in' %></p>
+<% end -%>
View
3 app/views/sessions/new.rhtml
@@ -0,0 +1,3 @@
+<div class="section_box">
+<%= render :partial => "form" %>
+</div>
View
2 app/views/tags/_all_tag_list.rhtml
@@ -1,9 +1,11 @@
<h1 style="display: inline;">All Tags</h1>
+<% if current_user.readwrite == true -%>
<%= add_button_remote(
"add_new_tag_button",
"Add new Tag",
url_for(:controller => "tags", :action => "all_new"),
"new_tag") %>
+<% end -%>
<div id="new_tag" style="display: none;">
</div>
<div id="tag_list_box">
View
7 app/views/tags/_tagged_nodes.rhtml
@@ -2,32 +2,37 @@
<div id="tag_header_<%= tag.id %>">
<%= h tag.name %>
<a id="show_tags_for_<%= tag.id %>" href="<%= url_for(:controller => "tags", :action => "all_edit", :id => tag.id) %>" class="toggle" toggle="tag_node_list_<%= tag.id %>" >(<%= node_count %> nodes)</a>
+<% if current_user.readwrite == true -%>
<%= edit_button("Edit", url_for(:controller => "tags", :action => "all_edit", :id => tag.id))%>
<%= remove_button_remote("delete_tag_#{tag.id}", "Delete",
url_for(:controller => "tags", :action => "all_destroy", :id => tag.id),
update_div_id,
"Really delete tag #{h tag.name}?"
) %>
+<% end -%>
</div>
<% div_style = visible ? "" : "display: none;" -%>
<div id="tag_node_list_<%= tag.id %>" class="tag_node_list" style="<%= div_style %>">
-
+<% if current_user.readwrite == true -%>
<% form_tag(url_for(:controller => "tags", :action => "all_node_add", :id => tag.id),
:id => "tag_#{tag.id}_add_node", :class => "remote_form", :update => "tag_list_#{tag.id}") do -%>
<%= text_field_tag("new_node", nil, { :id => "tag_new_node_#{tag.id}", :size => 10, :class => "autocomplete", :autocomplete_url => "#{url_for(:controller => "nodes", :action => "autocomplete")}" }) %>
<%= image_submit_tag(image_path("list-add.png")) %>
<%= spinner_tag("tag_#{tag.id}_add_node_spinner") %>
<% end -%>
+<% end -%>
<% tagged_nodes.each do |node| -%>
<table>
<tr>
<td><%= link_to("#{h node.description}", node_path(node)) %></td>
+ <% if current_user.readwrite == true -%>
<td><%= remove_button_remote("tag_list_#{tag.id}_node_#{node.id}", "Delete Tag from Node",
url_for(:controller => "tags", :action => "all_node_destroy", :id => tag.id, :node_id => node.id),
"tag_list_#{tag.id}",
"Really remove tag #{h tag.name} from #{h node.description}"
) %>
</td>
+ <% end -%>
</tr>
</table>
<% end -%>
View
2 app/views/tags/new.rhtml
@@ -1,4 +1,4 @@
<%= error_messages_for :tag %>
-<% form_for :tag, :url => tags_url(:node_id => @node.id) do |form| %>
+<% form_for :tag, :url => node_tags_path(:node_id => @node.id) do |form| %>
<%= render :partial => 'form', :locals => { :node => @node, :form => form } %>
<% end %>
View
15 app/views/users/_form.rhtml
@@ -0,0 +1,15 @@
+<%= error_messages_for :user %>
+<% unless for_edit %>
+<p><label for="login">Login</label><br/>
+<%= f.text_field :login %></p>
+<% end -%>
+<p><label for="password">Password</label><br/>
+<%= f.password_field :password %></p>
+
+<p><label for="password_confirmation">Confirm Password</label><br/>
+<%= f.password_field :password_confirmation %></p>
+
+<p><label for="readwrite">Read Write Access?</label><br/>
+<%= f.check_box :readwrite %>
+
+<p><%= submit_tag submit %></p>
View
6 app/views/users/edit.rhtml
@@ -0,0 +1,6 @@
+<div class="section_box">
+<h2>Editing <%= @user.login %></h2>
+<% form_for(:user, :url => user_path(@user), :html => { :method => :put }) do |f| -%>
+<%= render :partial => "form", :locals => { :submit => "Update", :for_edit => true, :f => f} %>
+<% end -%>
+</div>
View
27 app/views/users/index.rhtml
@@ -0,0 +1,27 @@
+<div class="section_box">
+ <h2>Users</h2><%= add_button("Add new User", new_user_path) %>
+ <table id="user_list" class="tablesorter">
+ <thead>
+ <tr>
+ <th>Login</th>
+ <th>Read Write Access?</th>
+ <th> </th>
+ </tr>
+ </thead>
+ <tbody>
+ <% @users.each do |user| -%>
+ <tr>
+ <td>
+ <%= h user.login %>
+ </td>
+ <td>
+ <%= user.readwrite ? "Yes" : "No" %>
+ </td>
+ <td>
+ <%= edit_button("Edit", edit_user_path(user))%>
+ <%= remove_button("Delete", user_path(user), "Delete user #{h user.login}?")%>
+ </tr>
+ <% end -%>
+ </tbody>
+ </table>
+</div>
View
6 app/views/users/new.rhtml
@@ -0,0 +1,6 @@
+<div class="section_box">
+<h2>Adding New User</h2>
+<% form_for(:user, :url => users_path) do |f| -%>
+<%= render :partial => "form", :locals => { :submit => "Add User", :f => f } %>
+<% end -%>
+</div>
View
2 bin/icagent
@@ -26,7 +26,7 @@ require 'optparse'
config = {
:uuidfile => File.dirname(__FILE__) + '/../icagent.uuid',
- :server => 'http://iclassify'
+ :server => 'https://iclassify'
}
opts = OptionParser.new do |opts|
opts.banner = "Usage: #{$0} [-d DIR|-r FILE] (options)"
View
24 bin/icpuppet
@@ -23,16 +23,25 @@
require 'rubygems'
require File.dirname(__FILE__) + '/../lib/iclassify'
require 'optparse'
+require 'highline/import'
config = {
- :server => 'http://iclassify'
+ :server => 'https://iclassify',
+ :user => ENV.has_key?('USER') ? ENV["USER"] : nil,
+ :passwd => nil
}
args = ARGV
opts = OptionParser.new do |opts|
opts.banner = "Usage: #{$0} [-s server] hostname"
opts.on("-s SERVER", "--server", "iClassify Server URL") do |s|
config[:server] = s
end
+ opts.on("-u user", "--user user", "User to authenticate with, defaults to USER env variable") do |u|
+ config[:user] = u
+ end
+ opts.on("-p passwd", "--passwd passwd", "Password to authenticate with") do |p|
+ config[:passwd] = p
+ end
opts.on_tail("-h", "--help", "Show this message") do
puts opts
exit
@@ -47,9 +56,20 @@ unless args.length == 1
exit 1
end
+unless config[:passwd]
+ config[:passwd] = HighLine.ask("Password: ") { |q| q.echo = "*" }
+end
+
+unless config[:user] && config[:passwd]
+ puts "You must provide a username and password."
+ puts opts.help
+ exit 1
+end
+
+
hostname = args[0]
-client = IClassify::Client.new(config[:server])
+client = IClassify::Client.new(config[:server], config[:user], config[:passwd])
begin
results = client.search("hostname:\"#{hostname}\" OR fqdn:\"#{hostname}\"")
rescue SocketError
View
23 bin/icsearch
@@ -23,9 +23,12 @@
require 'rubygems'
require File.dirname(__FILE__) + '/../lib/iclassify'
require 'optparse'
+require 'highline/import'
config = {
- :server => 'http://iclassify'
+ :server => 'https://iclassify',
+ :user => ENV.has_key?('USER') ? ENV['USER'] : nil,
+ :passwd => nil
}
opts = OptionParser.new do |opts|
opts.banner = "Usage: #{$0} (options) query"
@@ -35,6 +38,12 @@ opts = OptionParser.new do |opts|
opts.on("-t", "--tags", "Print tags or not, if attribs specified") do |t|
config[:tags] = t
end
+ opts.on("-u user", "--user user", "User to authenticate with, defaults to USER env variable") do |u|
+ config[:user] = u
+ end
+ opts.on("-p passwd", "--passwd passwd", "Password to authenticate with") do |p|
+ config[:passwd] = p
+ end
opts.on("-s server", "--server server", "iClassify Server URL") do |s|
config[:server] = s
end
@@ -52,9 +61,19 @@ if args.length != 1
exit 1
end
+unless config[:passwd]
+ config[:passwd] = HighLine.ask("Password: ") { |q| q.echo = "*" }
+end
+
+unless config[:user] && config[:passwd]
+ puts "You must provide a username and password."
+ puts opts.help
+ exit 1
+end
+
query = args[0]
-client = IClassify::Client.new(config[:server])
+client = IClassify::Client.new(config[:server], config[:user], config[:passwd])
begin
results = client.search(query)
rescue SocketError
View
2 bin/icwatcher
@@ -27,7 +27,7 @@ require 'tempfile'
require 'open3'
config = {
- :server => 'http://iclassify',
+ :server => 'https://iclassify',
:uuidfile => File.dirname(__FILE__) + '/../icagent.uuid',
:tmpfile => File.join(Dir::tmpdir, "icwatcher.digest"),
}
View
20 config/routes.rb
@@ -1,8 +1,22 @@
ActionController::Routing::Routes.draw do |map|
- map.resources :nodes, :path_prefix => "/rest", :name_prefix => "rest_", :controller => "rest_nodes"
- map.resources :tags, :path_prefix => "/rest", :name_prefix => "rest_", :controller => "rest_tags"
- map.resources :search, :path_prefix => "/rest", :name_prefix => "rest_", :controller => "rest_search"
+ map.resources :nodes,
+ :path_prefix => "/rest",
+ :name_prefix => "rest_",
+ :controller => "rest_nodes"
+
+ map.resources :tags,
+ :path_prefix => "/rest",
+ :name_prefix => "rest_",
+ :controller => "rest_tags"
+
+ map.resources :search,
+ :path_prefix => "/rest",
+ :name_prefix => "rest_",
+ :controller => "rest_search"
+
+ map.resources :users
+ map.resource :session, :controller => 'sessions'
map.rest_search "rest/search.:format",
:controller => "rest_search",
View
18 db/migrate/006_create_users.rb
@@ -0,0 +1,18 @@
+class CreateUsers < ActiveRecord::Migration
+ def self.up
+ create_table "users", :force => true do |t|
+ t.column :login, :string
+ t.column :email, :string
+ t.column :crypted_password, :string, :limit => 40
+ t.column :salt, :string, :limit => 40
+ t.column :created_at, :datetime
+ t.column :updated_at, :datetime
+ t.column :remember_token, :string
+ t.column :remember_token_expires_at, :datetime
+ end
+ end
+
+ def self.down
+ drop_table "users"
+ end
+end
View
16 db/migrate/007_create_admin_user.rb
@@ -0,0 +1,16 @@
+class CreateAdminUser < ActiveRecord::Migration
+ def self.up
+ down
+
+ admin_user = User.new(
+ :login => "admin",
+ :password => "iclassify",
+ :password_confirmation => "iclassify"
+ )
+ admin_user.save!
+ end
+
+ def self.down
+ User.delete_all
+ end
+end
View
11 db/migrate/008_update_node_for_auth.rb
@@ -0,0 +1,11 @@
+class UpdateNodeForAuth < ActiveRecord::Migration
+ def self.up
+ add_column :nodes, :crypted_password, :string, :limit => 40
+ add_column :nodes, :salt, :string, :limit => 40
+ end
+
+ def self.down
+ remove_column :nodes, :crypted_password
+ remove_column :nodes, :salt
+ end
+end
View
9 db/migrate/009_update_nodes_add_quarantined.rb
@@ -0,0 +1,9 @@
+class UpdateNodesAddQuarantined < ActiveRecord::Migration
+ def self.up
+ add_column :nodes, :quarantined, :boolean, :default => false
+ end
+
+ def self.down
+ remove_column :nodes, :quarantined
+ end
+end
View
9 db/migrate/010_update_user_table_add_read_write.rb
@@ -0,0 +1,9 @@
+class UpdateUserTableAddReadWrite < ActiveRecord::Migration
+ def self.up
+ add_column :users, :readwrite, :boolean, :default => true
+ end
+
+ def self.down
+ remove_column :users, :readwrite
+ end
+end
View
19 db/migrate/011_upgrade_node_objects.rb
@@ -0,0 +1,19 @@
+class UpgradeNodeObjects < ActiveRecord::Migration
+ require 'tmpdir'
+
+ def self.up
+ chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
+ nodes_to_upgrade = Node.find(:all, :conditions => "crypted_password is NULL" )
+ nodes_to_upgrade.each do |node|
+ newpass = ""
+ 1.upto(30) { |i| newpass << chars[rand(chars.size-1)] }
+ node.password = newpass
+ node.save!
+ node_uuid_filename = File.join(Dir.tmpdir, "#{node.description}.uuid")
+ puts "New UUID File: #{node_uuid_filename}"
+ File.open(node_uuid_filename, 'w') do |uuid_file|
+ uuid_file.puts("#{node.uuid}!#{node.crypted_password}")
+ end
+ end
+ end
+end
View
23 db/schema.rb
@@ -2,7 +2,7 @@
# migrations feature of ActiveRecord to incrementally modify your database, and
# then regenerate this schema definition.
-ActiveRecord::Schema.define(:version => 5) do
+ActiveRecord::Schema.define(:version => 11) do
create_table "attribs", :force => true do |t|
t.column "node_id", :integer, :null => false
@@ -15,9 +15,12 @@
end
create_table "nodes", :force => true do |t|
- t.column "uuid", :string, :limit => 38, :null => false
- t.column "description", :string
- t.column "notes", :text
+ t.column "uuid", :string, :limit => 38, :null => false
+ t.column "description", :string
+ t.column "notes", :text
+ t.column "crypted_password", :string, :limit => 40
+ t.column "salt", :string, :limit => 40
+ t.column "quarantined", :boolean, :default => false
end
create_table "nodes_tags", :id => false, :force => true do |t|
@@ -32,4 +35,16 @@
t.column "name", :string, :null => false
end
+ create_table "users", :force => true do |t|
+ t.column "login", :string
+ t.column "email", :string
+ t.column "crypted_password", :string, :limit => 40
+ t.column "salt", :string, :limit => 40
+ t.column "created_at", :datetime
+ t.column "updated_at", :datetime
+ t.column "remember_token", :string
+ t.column "remember_token_expires_at", :datetime
+ t.column "readwrite", :boolean, :default => true
+ end
+
end
View
140 lib/authenticated_system.rb
@@ -0,0 +1,140 @@
+module AuthenticatedSystem
+ UUIDREGEX = /^[[:xdigit:]]{8}[:-][[:xdigit:]]{4}[:-][[:xdigit:]]{4}[:-][[:xdigit:]]{4}[:-][[:xdigit:]]{12}$/
+
+ protected
+ # Returns true or false if the user is logged in.
+ # Preloads @current_user with the user model if they're logged in.
+ def logged_in?
+ current_user != :false
+ end
+
+ # Accesses the current user from the session. Set it to :false if login fails
+ # so that future calls do not hit the database.
+ def current_user
+ @current_user ||= (login_from_session || login_from_basic_auth || login_from_cookie || :false)
+ end
+
+ # Store the given user in the session.
+ def current_user=(new_user)
+ session[:user_type] = (new_user.nil? || new_user.is_a?(Symbol)) ? nil : new_user.class.to_s
+ session[:user] = (new_user.nil? || new_user.is_a?(Symbol)) ? nil : new_user.id
+ @current_user = new_user
+ end
+
+ # Check if the user is authorized
+ #
+ # Override this method in your controllers if you want to restrict access
+ # to only a few actions or if you want to check if the user
+ # has the correct rights.
+ #
+ # Example:
+ #
+ # # only allow nonbobs
+ # def authorized?
+ # current_user.login != "bob"
+ # end
+ def authorized?
+ logged_in?
+ end
+
+ # Filter method to enforce a login requirement.
+ #
+ # To require logins for all actions, use this in your controllers:
+ #
+ # before_filter :login_required
+ #
+ # To require logins for specific actions, use this in your controllers:
+ #
+ # before_filter :login_required, :only => [ :edit, :update ]
+ #
+ # To skip this in a subclassed controller:
+ #
+ # skip_before_filter :login_required
+ #
+ def login_required
+ authorized? || access_denied
+ end
+
+ # Redirect as appropriate when an access request fails.
+ #
+ # The default action is to redirect to the login screen.
+ #
+ # Override this method in your controllers if you want to have special
+ # behavior in case the user is not authorized
+ # to access the requested action. For example, a popup window might
+ # simply close itself.
+ def access_denied
+ respond_to do |accepts|
+ accepts.html do
+ store_location
+ redirect_to :controller => '/sessions', :action => 'new'
+ end
+ accepts.xml do
+ headers["Status"] = "Unauthorized"
+ headers["WWW-Authenticate"] = %(Basic realm="Web Password")
+ render :text => "Couldn't authenticate you", :status => '401 Unauthorized'
+ end
+ end
+ false
+ end
+
+ # Store the URI of the current request in the session.
+ #
+ # We can return to this location by calling #redirect_back_or_default.
+ def store_location
+ session[:return_to] = request.request_uri
+ end
+
+ # Redirect to the URI stored by the most recent store_location call or
+ # to the passed default.
+ def redirect_back_or_default(default)
+ session[:return_to] ? redirect_to_url(session[:return_to]) : redirect_to(default)
+ session[:return_to] = nil
+ end
+
+ # Inclusion hook to make #current_user and #logged_in?
+ # available as ActionView helper methods.
+ def self.included(base)
+ base.send :helper_method, :current_user, :logged_in?
+ end
+
+ # Called from #current_user. First attempt to login by the user id stored in the session.
+ def login_from_session
+ if session[:user]
+ if session[:user_type] == 'Node'
+ self.current_user = Node.find_by_id(session[:user])
+ else
+ self.current_user = User.find_by_id(session[:user])
+ end
+ end