From b1dc5aa7269fa48b9c581fd3157c780276af0806 Mon Sep 17 00:00:00 2001 From: Nathan Broadbent Date: Mon, 21 May 2012 19:06:47 +1200 Subject: [PATCH] Initial commit --- .gitignore | 4 ++ .travis.yml | 7 ++ Gemfile | 26 +++++++ MIT-LICENSE | 20 ++++++ README | 6 ++ Rakefile | 27 +++++++ app/models/err_observer.rb | 22 ++++++ app/models/notice_observer.rb | 38 ++++++++++ app/views/users/_fields.html.haml | 37 ++++++++++ app/views/users/index.html.haml | 23 ++++++ config.ru | 7 ++ config/cloudfuji.json | 8 +++ config/initializers/cloudfuji.rb | 10 +++ config/initializers/cloudfuji_config.rb | 28 ++++++++ config/mongoid.cloudfuji.yml | 8 +++ errbit_cloudfuji.gemspec | 22 ++++++ lib/errbit/cloudfuji.rb | 71 +++++++++++++++++++ .../cloudfuji/event_observers/app_observer.rb | 19 +++++ .../event_observers/user_observer.rb | 41 +++++++++++ lib/errbit_cloudfuji.rb | 6 ++ lib/errbit_cloudfuji/engine.rb | 17 +++++ lib/errbit_cloudfuji/version.rb | 5 ++ lib/tasks/cloudfuji.rake | 21 ++++++ spec/spec_helper.rb | 22 ++++++ 24 files changed, 495 insertions(+) create mode 100644 .gitignore create mode 100644 .travis.yml create mode 100644 Gemfile create mode 100644 MIT-LICENSE create mode 100644 README create mode 100644 Rakefile create mode 100644 app/models/err_observer.rb create mode 100644 app/models/notice_observer.rb create mode 100644 app/views/users/_fields.html.haml create mode 100644 app/views/users/index.html.haml create mode 100644 config.ru create mode 100644 config/cloudfuji.json create mode 100644 config/initializers/cloudfuji.rb create mode 100644 config/initializers/cloudfuji_config.rb create mode 100644 config/mongoid.cloudfuji.yml create mode 100644 errbit_cloudfuji.gemspec create mode 100644 lib/errbit/cloudfuji.rb create mode 100644 lib/errbit/cloudfuji/event_observers/app_observer.rb create mode 100644 lib/errbit/cloudfuji/event_observers/user_observer.rb create mode 100644 lib/errbit_cloudfuji.rb create mode 100644 lib/errbit_cloudfuji/engine.rb create mode 100644 lib/errbit_cloudfuji/version.rb create mode 100644 lib/tasks/cloudfuji.rake create mode 100644 spec/spec_helper.rb diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..54b6c8f --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +pkg/ +*.gem +Gemfile.lock +spec/internal/log/ diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..8efc384 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,7 @@ +lang: ruby + +rvm: + - 1.9.3 + +before_script: + - sh -c "psql -c 'create database ffcrm_cloudfuji_test;' -U postgres" diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..4706655 --- /dev/null +++ b/Gemfile @@ -0,0 +1,26 @@ +source :rubygems + +gem 'bundler_local_development', :group => :development, :require => false +begin + require 'bundler_local_development' +rescue LoadError +end + +gemspec + +gem 'cloudfuji', :git => 'git://github.com/cloudfuji/cloudfuji_client.git' + +group :test, :development do + gem 'pg' # Default database for testing +end + +group :test do + gem 'rspec' + gem 'combustion' + gem 'factory_girl' + unless ENV["CI"] + gem 'ruby-debug', :platform => :mri_18 + gem (RUBY_VERSION == "1.9.2" ? 'ruby-debug19' : 'debugger'), :platform => :mri_19 + end +end + diff --git a/MIT-LICENSE b/MIT-LICENSE new file mode 100644 index 0000000..bfe9381 --- /dev/null +++ b/MIT-LICENSE @@ -0,0 +1,20 @@ +Copyright (c) 2011 [name of plugin creator] + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README b/README new file mode 100644 index 0000000..dd1def4 --- /dev/null +++ b/README @@ -0,0 +1,6 @@ +Errbit - Cloudfuji Integration +==================================== + +Integrates Errbit with the Cloudfuji hosting platform. + +Copyright (c) 2012 Cloudfuji diff --git a/Rakefile b/Rakefile new file mode 100644 index 0000000..0e7d641 --- /dev/null +++ b/Rakefile @@ -0,0 +1,27 @@ +#!/usr/bin/env rake +begin + require 'bundler/setup' +rescue LoadError + puts 'You must `gem install bundler` and `bundle install` to run rake tasks' +end +Bundler.require :default, :development + +task :environment do + Combustion.initialize! +end +Combustion::Application.load_tasks + +class Combustion::Application + # Add migrations from all engines + Railties.engines.each do |engine| + config.paths['db/migrate'] += engine.paths['db/migrate'].existent + end +end + +desc 'Default: run spec tests.' +task :default => :spec + +# Let Combustion handle database preparation +Rake::Task["spec"].prerequisites.clear + +Bundler::GemHelper.install_tasks diff --git a/app/models/err_observer.rb b/app/models/err_observer.rb new file mode 100644 index 0000000..768cbef --- /dev/null +++ b/app/models/err_observer.rb @@ -0,0 +1,22 @@ +class ErrObserver < Mongoid::Observer + def after_create(err) + if ::Cloudfuji::Platform.on_cloudfuji? + human_message = issue_title(err.problem) + human_message += " see more at #{Rails.application.routes.url_helpers.app_err_url(err.problem.app, err, :host => ENV['CLOUDFUJI_DOMAIN'])}" + event = { + :category => :app, + :name => :errored, + :data => { + :human => human_message, + :source => "Errbit", + :url => Rails.application.routes.url_helpers.app_err_url(err.problem.app, err, :host => ENV['CLOUDFUJI_DOMAIN']) + } + } + ::Cloudfuji::Event.publish(event) + end + end + + def issue_title(problem) + "[#{ problem.environment }][#{ problem.where }] #{problem.message.to_s.truncate(100)}" + end +end diff --git a/app/models/notice_observer.rb b/app/models/notice_observer.rb new file mode 100644 index 0000000..55ab82d --- /dev/null +++ b/app/models/notice_observer.rb @@ -0,0 +1,38 @@ +class NoticeObserver < Mongoid::Observer + def after_create(notice) + if ::Cloudfuji::Platform.on_cloudfuji? + @notice = notice + @err = notice.err + @app = notice.problem.app + + human_message = notice_title(notice.err.problem) + human_message += " see more at #{Rails.application.routes.url_helpers.app_err_url(@app, @notice.problem, :host => ENV['CLOUDFUJI_DOMAIN'])}" + event = { + :category => :app, + :name => :errored, + :data => { + :human => human_message, + :environment_name => @notice.environment_name, + :occurrences => @notice.problem.notices_count, + :message => @notice.message, + :app_backtrace => @notice.app_backtrace, + :request => @notice.request, + :source => "Errbit", + :url => Rails.application.routes.url_helpers.app_err_url(@app, @err, :host => ENV['CLOUDFUJI_DOMAIN']) + } + } + + ::Cloudfuji::Event.publish(event) + + puts "Notifying: #{@app.watchers.inspect}" + @app.watchers.each do |watcher| + ido_id = watcher.user.ido_id + Cloudfuji::User.notify(ido_id, "Site Error", human_message, "site_error") unless ido_id.blank? + end + end + end + + def notice_title(notice) + "[#{@app.name}][#{@notice.environment_name}] #{@notice.message}" + end +end diff --git a/app/views/users/_fields.html.haml b/app/views/users/_fields.html.haml new file mode 100644 index 0000000..cdb825f --- /dev/null +++ b/app/views/users/_fields.html.haml @@ -0,0 +1,37 @@ += errors_for @user + +.required + = f.label :name + = f.text_field :name + +- if Errbit::Config.user_has_username + .required + = f.label :username + = f.text_field :username + +.required + = f.label :email + = f.text_field :email + +.required + = f.label 'Entries per page' + = f.select :per_page, [10, 20, 30, 50, 75, 100] + +.required + = f.label :time_zone + = f.time_zone_select :time_zone, ActiveSupport::TimeZone.us_zones + +- unless Cloudfuji::Platform.on_cloudfuji? + .required + = f.label :password + = f.password_field :password + + .required + = f.label :password_confirmation + = f.password_field :password_confirmation + +- if current_user.admin? + .checkbox + = f.check_box :admin + = f.label :admin, 'Admin?' + diff --git a/app/views/users/index.html.haml b/app/views/users/index.html.haml new file mode 100644 index 0000000..ee5c8e6 --- /dev/null +++ b/app/views/users/index.html.haml @@ -0,0 +1,23 @@ +- content_for :title, 'Users' +- if not Devise.on_cloudfuji? + - content_for :action_bar do + %span= link_to('Add a New User', new_user_path, :class => 'add') + +%table + %thead + %tr + %th Name + - if Errbit::Config.user_has_username + %th Username + %th.main Email + %th Admin? + %tbody + - @users.each do |user| + %tr + %td.nowrap= link_to user.name, user_path(user) + - if Errbit::Config.user_has_username + %td= user.username + %td= user.email + %td= user.admin? ? 'Y' : 'N' += paginate @users + diff --git a/config.ru b/config.ru new file mode 100644 index 0000000..d2881ce --- /dev/null +++ b/config.ru @@ -0,0 +1,7 @@ +require 'rubygems' +require 'bundler' + +Bundler.require :default, :development + +Combustion.initialize! +run Combustion::Application diff --git a/config/cloudfuji.json b/config/cloudfuji.json new file mode 100644 index 0000000..62c1cd0 --- /dev/null +++ b/config/cloudfuji.json @@ -0,0 +1,8 @@ +{ + "platform": "rails", + "platform_version": 3, + "ruby_version": "1.9.2", + "sql": false, + "mongodb": true, + "project_name": "errbit" +} diff --git a/config/initializers/cloudfuji.rb b/config/initializers/cloudfuji.rb new file mode 100644 index 0000000..3fa551d --- /dev/null +++ b/config/initializers/cloudfuji.rb @@ -0,0 +1,10 @@ +require 'errbit/cloudfuji' + +Errbit::Application.configure do + # Register observers to fire Cloudfuji events + config.mongoid.observers = :err_observer, :notice_observer + + # Set default host for ActionMailer + default_host = ENV['ERRBIT_HOST'] || ENV['BUSHIDO_DOMAIN'] + config.action_mailer.default_url_options = { :host => default_host } if default_host +end diff --git a/config/initializers/cloudfuji_config.rb b/config/initializers/cloudfuji_config.rb new file mode 100644 index 0000000..5c22923 --- /dev/null +++ b/config/initializers/cloudfuji_config.rb @@ -0,0 +1,28 @@ +if ENV['HOSTING_PLATFORM'] == 'cloudfuji' + require 'ostruct' + Errbit::Config = OpenStruct.new + + puts "Loading Cloudfuji config" + Errbit::Config.host = ENV['CLOUDFUJI_DOMAIN'] + Errbit::Config.email_from = ENV['SMTP_USER'] + Errbit::Config.email_at_notices = [1,3,10] #ENV['ERRBIT_EMAIL_AT_NOTICES'] + Errbit::Config.confirm_resolve_err = true + Errbit::Config.user_has_ido_id = true + Errbit::Config.allow_comments_with_issue_tracker = true + + Errbit::Config.smtp_settings = { + :address => ENV["SMTP_SERVER"], + :port => ENV["SMTP_PORT"], + :authentication => ENV["SMTP_AUTHENTICATION"], + :user_name => ENV["SMTP_USER"], + :password => ENV["SMTP_PASSWORD"], + :domain => ENV["SMTP_DOMAIN"] + } + + Errbit::Config.devise_modules = [:cloudfuji_authenticatable, + :rememberable, + :trackable, + :token_authenticatable] + + puts "Devise modules: #{Errbit::Config.devise_modules.inspect}" +end diff --git a/config/mongoid.cloudfuji.yml b/config/mongoid.cloudfuji.yml new file mode 100644 index 0000000..1f6cfeb --- /dev/null +++ b/config/mongoid.cloudfuji.yml @@ -0,0 +1,8 @@ +# Mongoid Configuration for MongoHQ on Cloudfuji +# ============================================ + +development: + uri: <%= ENV['MONGODB_URL'] %> + +production: + uri: <%= ENV['MONGODB_URL'] %> diff --git a/errbit_cloudfuji.gemspec b/errbit_cloudfuji.gemspec new file mode 100644 index 0000000..e42cb9a --- /dev/null +++ b/errbit_cloudfuji.gemspec @@ -0,0 +1,22 @@ +# -*- encoding: utf-8 -*- +$:.push File.expand_path('../lib', __FILE__) +require 'errbit_cloudfuji/version' + +Gem::Specification.new do |s| + s.name = 'errbit_cloudfuji' + s.authors = ['Sean Grove', 'Nathan Broadbent'] + s.email = 's@cloudfuji.com' + s.homepage = 'http://cloudfuji.com' + s.summary = 'Errbit - Cloudfuji Integration' + s.description = 'Integrates Errbit with the Cloudfuji hosting platform.' + s.files = `git ls-files`.split("\n") + s.version = Errbit::Cloudfuji::VERSION + + s.add_development_dependency 'rspec-rails', '~> 2.6' + s.add_development_dependency 'capybara' + s.add_development_dependency 'combustion' + + s.add_dependency 'cloudfuji', '>= 0.0.42' + s.add_dependency 'devise_cloudfuji_authenticatable' + +end diff --git a/lib/errbit/cloudfuji.rb b/lib/errbit/cloudfuji.rb new file mode 100644 index 0000000..7bef188 --- /dev/null +++ b/lib/errbit/cloudfuji.rb @@ -0,0 +1,71 @@ +module Errbit + module Cloudfuji + class << self + def enable_cloudfuji! + load_hooks! + extend_user! + extend_notice! + disable_devise_for_cloudfuji_controllers! + end + + def extend_user! + puts "Extending the user model" + User.instance_eval do + validates_presence_of :ido_id + validates_uniqueness_of :ido_id + end + + User.class_eval do + def cloudfuji_extra_attributes(extra_attributes) + self.name = "#{extra_attributes['first_name'].to_s} #{extra_attributes['last_name'].to_s}" + self.email = extra_attributes["email"] + self.admin = true + end + end + end + + def extend_notice! + Notice.class_eval do + def publish_cloudfuji_event + human_message = "App at #{server_environment['hostname']} error" + ::Cloudfuji::Event.publish({ + :category => :app, + :name => :error, + :data => { + :human => human_message, + :source => "Errbit", + :url => "#{ENV['PUBLIC_URL']}/#tickets/#{self.to_param}" + } + }) + end + end + end + + def load_hooks! + Dir["#{Dir.pwd}/lib/cloudfuji/**/*.rb"].each { |file| require file } + end + + # Temporary hack because all routes require authentication in + # Errbit + def disable_devise_for_cloudfuji_controllers! + puts "Disabling devise auth protection on cloudfuji controllers" + + ::Cloudfuji::DataController.instance_eval { before_filter :authenticate_user!, :except => [:index] } + ::Cloudfuji::EnvsController.instance_eval { before_filter :authenticate_user!, :except => [:update] } + ::Cloudfuji::MailController.instance_eval { before_filter :authenticate_user!, :except => [:index] } + + puts "Devise checks disabled for Cloudfuji controllers" + end + end + end +end + +if Cloudfuji::Platform.on_cloudfuji? + class CloudfujiRailtie < Rails::Railtie + config.to_prepare do + puts "Enabling Cloudfuji" + Errbit::Cloudfuji.enable_cloudfuji! + puts "Finished enabling Cloudfuji" + end + end +end diff --git a/lib/errbit/cloudfuji/event_observers/app_observer.rb b/lib/errbit/cloudfuji/event_observers/app_observer.rb new file mode 100644 index 0000000..b2106f6 --- /dev/null +++ b/lib/errbit/cloudfuji/event_observers/app_observer.rb @@ -0,0 +1,19 @@ +module Errbit + module Cloudfuji + module EventObservers + class AppObserver < ::Cloudfuji::EventObserver + def app_claimed + puts "Updating #{User.first.inspect} with incoming data #{params.inspect}" + puts "Devise username column: #{::Devise.cas_username_column}=" + puts "Setting username to: #{params.try(:[], 'ido_id')}" + + user = User.first + user.email = params['data'].try(:[], 'email') + user.name = user.email.split('@').first + user.send("#{::Devise.cas_username_column}=".to_sym, params['data'].try(:[], 'ido_id')) + user.save + end + end + end + end +end diff --git a/lib/errbit/cloudfuji/event_observers/user_observer.rb b/lib/errbit/cloudfuji/event_observers/user_observer.rb new file mode 100644 index 0000000..88aa572 --- /dev/null +++ b/lib/errbit/cloudfuji/event_observers/user_observer.rb @@ -0,0 +1,41 @@ +module Errbit + module Cloudfuji + module EventObservers + class AppObserver < ::Cloudfuji::EventObserver + def user_added + puts "Adding a new user with incoming data #{params.inspect}" + puts "Devise username column: #{::Devise.cas_username_column}=" + puts "Setting username to: #{params['data'].try(:[], 'ido_id')}" + + user = User.new(:email => params['data'].try(:[], 'email')) + user.name = user.email.split('@').first + user.send("#{::Devise.cas_username_column}=".to_sym, params['data'].try(:[], 'ido_id')) + user.save + end + + def user_removed + puts "Removing user based on incoming data #{params.inspect}" + puts "Devise username column: #{::Devise.cas_username_column}=" + + ido_id = params['data'].try(:[], 'ido_id') + + ido_id and + User.exists?(:conditions => {::Devise.cas_username_column => ido_id}) and + User.where(::Devise.cas_username_column => ido_id).destroy + end + + def user_updated + puts "Updating user based on incoming data #{params.inspect}" + puts "Devise username column: #{::Devise.cas_username_column}=" + ido_id = params['data'].try(:[], 'ido_id') + + if ido_id and User.exists?(:conditions => {::Devise.cas_username_column => ido_id}) + user = User.where(::Devise.cas_username_column => ido_id).first + user.cloudfuji_extra_attributes(params['data']) + user.save + end + end + end + end + end +end diff --git a/lib/errbit_cloudfuji.rb b/lib/errbit_cloudfuji.rb new file mode 100644 index 0000000..ed51f88 --- /dev/null +++ b/lib/errbit_cloudfuji.rb @@ -0,0 +1,6 @@ +# Gem Dependencies +require 'cloudfuji' +require 'devise_cloudfuji_authenticatable' + +# Rails Engine +require 'errbit_cloudfuji/engine' diff --git a/lib/errbit_cloudfuji/engine.rb b/lib/errbit_cloudfuji/engine.rb new file mode 100644 index 0000000..6f0a8e8 --- /dev/null +++ b/lib/errbit_cloudfuji/engine.rb @@ -0,0 +1,17 @@ +# Override engine view paths so that this gem's views can override application views +Rails::Engine.initializers.detect{|i| i.name == :add_view_paths }. + instance_variable_set("@block", Proc.new { + views = paths["app/views"].to_a + unless views.empty? + ActiveSupport.on_load(:action_controller){ append_view_path(views) } + ActiveSupport.on_load(:action_mailer){ append_view_path(views) } + end + } +) + +module Errbit + module Cloudfuji + class Engine < Rails::Engine + end + end +end diff --git a/lib/errbit_cloudfuji/version.rb b/lib/errbit_cloudfuji/version.rb new file mode 100644 index 0000000..f328aa9 --- /dev/null +++ b/lib/errbit_cloudfuji/version.rb @@ -0,0 +1,5 @@ +module Errbit + module Cloudfuji + VERSION = '0.1.0' + end +end diff --git a/lib/tasks/cloudfuji.rake b/lib/tasks/cloudfuji.rake new file mode 100644 index 0000000..6dbfc5b --- /dev/null +++ b/lib/tasks/cloudfuji.rake @@ -0,0 +1,21 @@ +require 'fileutils' + +namespace :cloudfuji do + + desc "Copys of example config files" + task :copy_configs do + unless File.exist? Rails.root.join('config/mongoid.yml') + FileUtils.cp File.expand_path("../../../config/mongoid.cloudfuji.yml", __FILE__), + Rails.root.join('config/mongoid.yml') + end + end + + desc "Run the initial setup for a Busido app. Copies config files and seeds db." + task :install do + Rake::Task['cloudfuji:copy_configs'].execute + puts "\n" + Rake::Task['db:seed'].invoke + puts "\n" + Rake::Task['db:mongoid:create_indexes'].invoke + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100644 index 0000000..9f11dbe --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,22 @@ +require 'rubygems' +require 'bundler' +require 'rails/all' + +Bundler.require :default, :development + +require 'rspec/rails' +require 'factory_girl' +require 'ffaker' + +# Load factories from spec/factories +Dir[File.expand_path("../factories/*.rb", __FILE__)].each {|factory| require factory } + +Combustion.initialize! + +RSpec.configure do |config| + config.use_transactional_fixtures = true +end + +# Cloudfuji::Platform.on_cloudfuji? is false, +# so we need to enable it manually +Errbit::Cloudfuji.enable_cloudfuji!