appoxy_rails 0.0.6
Sign up to get free protection for your applications and to get access to all the features.
- data/README.markdown +1 -0
- data/lib/api/api_controller.rb +106 -0
- data/lib/api/client.rb +110 -0
- data/lib/api/client_helper.rb +32 -0
- data/lib/api/signatures.rb +26 -0
- data/lib/appoxy_api.rb +10 -0
- data/lib/appoxy_sessions.rb +6 -0
- data/lib/appoxy_ui.rb +2 -0
- data/lib/sessions/application_controller.rb +82 -0
- data/lib/sessions/sessions_controller.rb +119 -0
- data/lib/sessions/shareable.rb +206 -0
- data/lib/sessions/user.rb +76 -0
- data/lib/sessions/users_controller.rb +122 -0
- data/lib/ui/application_helper.rb +35 -0
- metadata +89 -0
data/README.markdown
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
Nada.
|
@@ -0,0 +1,106 @@
|
|
1
|
+
module Appoxy
|
2
|
+
|
3
|
+
module Api
|
4
|
+
|
5
|
+
# The api controllers that use this should set:
|
6
|
+
# protect_from_forgery :only => [] # can add methods to here, eg: :create, :update, :destroy
|
7
|
+
|
8
|
+
# rescue_from SigError, :with => :send_error
|
9
|
+
# rescue_from Api::ApiError, :with => :send_error
|
10
|
+
# before_filter :verify_signature(params)
|
11
|
+
|
12
|
+
# Your Controller must define a secret_key_for_signature method which will return the secret key to use to generate signature.
|
13
|
+
|
14
|
+
module ApiController
|
15
|
+
|
16
|
+
def verify_signature
|
17
|
+
params2 = nil
|
18
|
+
if request.put? || request.post?
|
19
|
+
# We'll extract params from body instead here
|
20
|
+
# todo: maybe check for json format first in case this is a file or something?
|
21
|
+
body = request.body.read
|
22
|
+
puts 'body=' + body.inspect
|
23
|
+
params2 = ActiveSupport::JSON.decode(body)
|
24
|
+
puts 'params2=' + params2.inspect
|
25
|
+
params.merge! params2
|
26
|
+
end
|
27
|
+
|
28
|
+
#operation = "#{controller_name}/#{action_name}"
|
29
|
+
operation = request.env["PATH_INFO"].gsub(/\/api\//, "")# here we're getting original request url'
|
30
|
+
puts "XXX " + operation
|
31
|
+
|
32
|
+
#getting clean params (without parsed via routes)
|
33
|
+
params_for_signature = params2||request.query_parameters
|
34
|
+
#removing mandatory params
|
35
|
+
params_for_signature = params_for_signature.delete_if {|key, value| ["access_key", "sigv", "sig", "timestamp"].include? key}
|
36
|
+
|
37
|
+
|
38
|
+
#p "params " +operation+Appoxy::Api::Signatures.hash_to_s(params_for_signature)
|
39
|
+
access_key = params["access_key"]
|
40
|
+
sigv = params["sigv"]
|
41
|
+
timestamp = params["timestamp"]
|
42
|
+
sig = params["sig"]
|
43
|
+
|
44
|
+
raise Appoxy::Api::ApiError, "No access_key" if access_key.nil?
|
45
|
+
raise Appoxy::Api::ApiError, "No sigv" if sigv.nil?
|
46
|
+
raise Appoxy::Api::ApiError, "No timestamp" if timestamp.nil?
|
47
|
+
raise Appoxy::Api::ApiError, "No sig" if sig.nil?
|
48
|
+
timestamp2 = Appoxy::Api::Signatures.generate_timestamp(Time.now.gmtime)
|
49
|
+
raise Appoxy::Api::ApiError, "Request timed out!" unless (Time.parse(timestamp2)-Time.parse(timestamp))<60 # deny all requests older than 60 seconds
|
50
|
+
# Get application defined secret_key
|
51
|
+
secret_key = secret_key_for_signature(access_key)
|
52
|
+
sig2 = Appoxy::Api::Signatures.generate_signature(operation+Appoxy::Api::Signatures.hash_to_s(params_for_signature), timestamp, secret_key)
|
53
|
+
#p "signature 1 " + sig2 + " signature 2 " + sig
|
54
|
+
raise Appoxy::Api::ApiError, "Invalid signature!" unless sig == sig2
|
55
|
+
|
56
|
+
puts 'Verified OK'
|
57
|
+
true
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
def sig_should
|
63
|
+
raise "You didn't define a sig_should method in your controller!"
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
def send_ok(msg={})
|
68
|
+
response_as_string = '' # in case we want to add debugging or something
|
69
|
+
# respond_to do |format|
|
70
|
+
# format.json { render :json=>msg }
|
71
|
+
response_as_string = render_to_string :json => msg
|
72
|
+
render :json => response_as_string
|
73
|
+
# end
|
74
|
+
true
|
75
|
+
end
|
76
|
+
|
77
|
+
|
78
|
+
def send_error(statuscode_or_error, msg=nil)
|
79
|
+
exc = nil
|
80
|
+
if statuscode_or_error.is_a? Exception
|
81
|
+
exc = statuscode_or_error
|
82
|
+
statuscode_or_error = 400
|
83
|
+
msg = exc.message
|
84
|
+
end
|
85
|
+
# deprecate status, should use status_code
|
86
|
+
json_msg = {"status_code"=>statuscode_or_error, "msg"=>msg}
|
87
|
+
render :json=>json_msg, :status=>statuscode_or_error
|
88
|
+
true
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
class ApiError < StandardError
|
96
|
+
|
97
|
+
def initialize(msg=nil)
|
98
|
+
super(msg)
|
99
|
+
|
100
|
+
end
|
101
|
+
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
data/lib/api/client.rb
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
module Appoxy
|
2
|
+
module Api
|
3
|
+
|
4
|
+
require 'rest_client'
|
5
|
+
|
6
|
+
# Subclass must define:
|
7
|
+
# host: endpoint url for service
|
8
|
+
class Client
|
9
|
+
|
10
|
+
attr_accessor :host, :access_key, :secret_key
|
11
|
+
|
12
|
+
|
13
|
+
def initialize(host, access_key, secret_key, options={})
|
14
|
+
@host = host
|
15
|
+
@access_key = access_key
|
16
|
+
@secret_key = secret_key
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
def get(method, params={}, options={})
|
21
|
+
begin
|
22
|
+
# ClientHelper.run_http(host, access_key, secret_key, :get, method, nil, params)
|
23
|
+
parse_response RestClient.get(append_params(url(method), add_params(method, params)), headers)
|
24
|
+
rescue RestClient::BadRequest => ex
|
25
|
+
# puts ex.http_body
|
26
|
+
raise "Bad Request: " + ActiveSupport::JSON.decode(ex.http_body)["msg"].to_s
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
def post(method, params={}, options={})
|
32
|
+
begin
|
33
|
+
parse_response RestClient.post(url(method), add_params(method, params).to_json, headers)
|
34
|
+
#ClientHelper.run_http(host, access_key, secret_key, :post, method, nil, params)
|
35
|
+
rescue RestClient::BadRequest => ex
|
36
|
+
# puts ex.http_body
|
37
|
+
raise "Bad Request: " + ActiveSupport::JSON.decode(ex.http_body)["msg"].to_s
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
def put(method, body, options={})
|
44
|
+
begin
|
45
|
+
parse_response RestClient.put(url(method), add_params(method, body).to_json, headers)
|
46
|
+
#ClientHelper.run_http(host, access_key, secret_key, :put, method, body, nil)
|
47
|
+
rescue RestClient::BadRequest => ex
|
48
|
+
# puts ex.http_body
|
49
|
+
raise "Bad Request: " + ActiveSupport::JSON.decode(ex.http_body)["msg"].to_s
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
|
54
|
+
def delete(method, params={}, options={})
|
55
|
+
begin
|
56
|
+
parse_response RestClient.delete(append_params(url(method), add_params(method, params)))
|
57
|
+
rescue RestClient::BadRequest => ex
|
58
|
+
raise "Bad Request: " + ActiveSupport::JSON.decode(ex.http_body)["msg"].to_s
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
|
63
|
+
def url(command_path)
|
64
|
+
url = host + command_path
|
65
|
+
url
|
66
|
+
end
|
67
|
+
|
68
|
+
|
69
|
+
def add_params(command_path, hash)
|
70
|
+
ts = Appoxy::Api::Signatures.generate_timestamp(Time.now.gmtime)
|
71
|
+
#p "hash_to s" + command_path + Appoxy::Api::Signatures.hash_to_s(hash)
|
72
|
+
sig = Appoxy::Api::Signatures.generate_signature(command_path + Appoxy::Api::Signatures.hash_to_s(hash), ts, secret_key)
|
73
|
+
extra_params = {'sigv'=>"0.1", 'sig' => sig, 'timestamp' => ts, 'access_key' => access_key}
|
74
|
+
hash.merge!(extra_params)
|
75
|
+
|
76
|
+
end
|
77
|
+
|
78
|
+
|
79
|
+
def append_params(host, params)
|
80
|
+
host += "?"
|
81
|
+
i = 0
|
82
|
+
params.each_pair do |k, v|
|
83
|
+
host += "&" if i > 0
|
84
|
+
host += k + "=" + CGI.escape(v)
|
85
|
+
i+=1
|
86
|
+
end
|
87
|
+
return host
|
88
|
+
end
|
89
|
+
|
90
|
+
|
91
|
+
def headers
|
92
|
+
user_agent = "Appoxy API Ruby Client"
|
93
|
+
headers = {'User-Agent' => user_agent}
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
def parse_response(response)
|
98
|
+
begin
|
99
|
+
return ActiveSupport::JSON.decode(response.to_s)
|
100
|
+
rescue => ex
|
101
|
+
puts 'response that caused error = ' + response.to_s
|
102
|
+
raise ex
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module Appoxy
|
2
|
+
module Api
|
3
|
+
|
4
|
+
require 'rest_client'
|
5
|
+
|
6
|
+
module ClientHelper
|
7
|
+
|
8
|
+
|
9
|
+
end
|
10
|
+
|
11
|
+
class ClientError < StandardError
|
12
|
+
|
13
|
+
attr_reader :response_hash
|
14
|
+
|
15
|
+
def initialize(class_name, response_hash)
|
16
|
+
puts 'response-hash=' + response_hash.inspect
|
17
|
+
super("#{class_name} - #{response_hash["msg"]}")
|
18
|
+
@response_hash = response_hash
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class ServiceError < StandardError
|
23
|
+
attr_reader :body
|
24
|
+
|
25
|
+
def initialize(class_name, body)
|
26
|
+
super("#{class_name}")
|
27
|
+
@body = body
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
module Appoxy
|
2
|
+
module Api
|
3
|
+
module Signatures
|
4
|
+
|
5
|
+
|
6
|
+
def self.generate_timestamp(gmtime)
|
7
|
+
return gmtime.strftime("%Y-%m-%dT%H:%M:%SZ")
|
8
|
+
end
|
9
|
+
|
10
|
+
|
11
|
+
def self.generate_signature(operation, timestamp, secret_key)
|
12
|
+
my_sha_hmac = Digest::HMAC.digest(operation + timestamp, secret_key, Digest::SHA1)
|
13
|
+
my_b64_hmac_digest = Base64.encode64(my_sha_hmac).strip
|
14
|
+
return my_b64_hmac_digest
|
15
|
+
end
|
16
|
+
|
17
|
+
|
18
|
+
def self.hash_to_s(hash)
|
19
|
+
str = ""
|
20
|
+
hash.each_pair {|key, value| str+= "#{key}#{value}" }
|
21
|
+
#removing all characters that could differ after parsing with rails
|
22
|
+
return str.delete "\"\/:{}[]\' T"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
data/lib/appoxy_api.rb
ADDED
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'active_support/core_ext'
|
2
|
+
require 'digest/hmac'
|
3
|
+
require 'net/http'
|
4
|
+
require 'base64'
|
5
|
+
|
6
|
+
require File.join(File.dirname(__FILE__), "api", "api_controller")
|
7
|
+
require File.join(File.dirname(__FILE__), "api", "client_helper")
|
8
|
+
require File.join(File.dirname(__FILE__), "api", "signatures")
|
9
|
+
require File.join(File.dirname(__FILE__), "api", "client")
|
10
|
+
|
@@ -0,0 +1,6 @@
|
|
1
|
+
require 'simple_record'
|
2
|
+
require File.join(File.dirname(__FILE__), "sessions", "user")
|
3
|
+
require File.join(File.dirname(__FILE__), "sessions", "application_controller")
|
4
|
+
require File.join(File.dirname(__FILE__), "sessions", "sessions_controller")
|
5
|
+
require File.join(File.dirname(__FILE__), "sessions", "users_controller")
|
6
|
+
require File.join(File.dirname(__FILE__), "sessions", "shareable")
|
data/lib/appoxy_ui.rb
ADDED
@@ -0,0 +1,82 @@
|
|
1
|
+
module Appoxy
|
2
|
+
|
3
|
+
module Sessions
|
4
|
+
module ApplicationController
|
5
|
+
|
6
|
+
|
7
|
+
def logout_keeping_session!
|
8
|
+
@current_user = nil # not logged in, and don't do it for me
|
9
|
+
session[:user_id] = nil # keeps the session but kill our variable
|
10
|
+
end
|
11
|
+
|
12
|
+
|
13
|
+
def logged_in?
|
14
|
+
#puts 'logged_in??'
|
15
|
+
#puts 'current_user=' + current_user.inspect
|
16
|
+
current_user
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
def current_user=(new_user)
|
21
|
+
session[:user_id] = new_user ? new_user.id : nil
|
22
|
+
@current_user = new_user
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
def current_user
|
27
|
+
@current_user ||= (login_from_session)
|
28
|
+
@current_user
|
29
|
+
end
|
30
|
+
|
31
|
+
|
32
|
+
def login_from_session
|
33
|
+
#puts 'Login from session=' + session[:user_id].inspect
|
34
|
+
::User.find_by_id(session[:user_id]) if session[:user_id]
|
35
|
+
end
|
36
|
+
|
37
|
+
#
|
38
|
+
# helper_method :logged_in?
|
39
|
+
# helper_method :current_user
|
40
|
+
|
41
|
+
|
42
|
+
protected
|
43
|
+
|
44
|
+
def random_string(length=10)
|
45
|
+
chars = 'abcdefghjkmnpqrstuvwxyzABCDEFGHJKLMNPQRSTUVWXYZ23456789'
|
46
|
+
password = ''
|
47
|
+
length.times { password << chars[rand(chars.size)] }
|
48
|
+
password
|
49
|
+
end
|
50
|
+
|
51
|
+
def authenticate
|
52
|
+
if !logged_in?
|
53
|
+
flash[:warning] = "You need to login to access this page."
|
54
|
+
session[:return_to] = request.request_uri # return to after logging in
|
55
|
+
puts "ac=" + params[:ac].inspect
|
56
|
+
if params[:user_id] && params[:ac]
|
57
|
+
# todo: should we store ac in cookie? Make it easier to pass around
|
58
|
+
cookies[:ac] = params[:ac]
|
59
|
+
# then from an invite
|
60
|
+
user = ::User.find(params[:user_id])
|
61
|
+
if user && user.password.blank? # is this the best way to decide of user has not logged in? Could also check status.
|
62
|
+
redirect_to :controller=>"users", :action=>"new", :email=>user.email, :ac=>params[:ac]
|
63
|
+
return
|
64
|
+
end
|
65
|
+
end
|
66
|
+
redirect_to :controller=>"sessions", :action=>"new", :ac=>params[:ac]
|
67
|
+
end
|
68
|
+
|
69
|
+
after_authenticate
|
70
|
+
|
71
|
+
end
|
72
|
+
def after_authenticate
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
end
|
81
|
+
|
82
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
module Appoxy
|
2
|
+
|
3
|
+
module Sessions
|
4
|
+
module SessionsController
|
5
|
+
|
6
|
+
def new
|
7
|
+
|
8
|
+
end
|
9
|
+
|
10
|
+
def create
|
11
|
+
before_create
|
12
|
+
|
13
|
+
logout_keeping_session!
|
14
|
+
|
15
|
+
#puts 'params=' + params.inspect
|
16
|
+
@email = params[:email]
|
17
|
+
@has_password = params[:has_password]
|
18
|
+
#puts 'has_pass? ' + @has_password.inspect
|
19
|
+
|
20
|
+
if params[:has_password].blank?
|
21
|
+
flash[:error] = "Please click the radio button to let us know if you have a password or not."
|
22
|
+
render :action=>"new"
|
23
|
+
return
|
24
|
+
end
|
25
|
+
|
26
|
+
if @has_password == "true"
|
27
|
+
user = ::User.find_by_email(@email)
|
28
|
+
# user = User.authenticate(@email, params[:password])
|
29
|
+
if user && user.authenticate(params[:password])
|
30
|
+
self.current_user = user
|
31
|
+
flash[:info] = "Logged in successfully."
|
32
|
+
orig_url = session[:return_to]
|
33
|
+
puts 'orig_url = ' + orig_url.to_s
|
34
|
+
session[:return_to] = nil
|
35
|
+
if !orig_url.nil?
|
36
|
+
redirect_to orig_url # if entered via a different url
|
37
|
+
else
|
38
|
+
after_create
|
39
|
+
end
|
40
|
+
user.last_login = Time.now
|
41
|
+
user.save(:dirty=>true)
|
42
|
+
else
|
43
|
+
flash[:info] = "Invalid email or password. Please try again."
|
44
|
+
render :action => 'new'
|
45
|
+
end
|
46
|
+
else
|
47
|
+
# new user
|
48
|
+
|
49
|
+
redirect_to (new_user_path + "?email=#{@email}")
|
50
|
+
end
|
51
|
+
|
52
|
+
end
|
53
|
+
|
54
|
+
def before_create
|
55
|
+
|
56
|
+
end
|
57
|
+
def after_create
|
58
|
+
|
59
|
+
end
|
60
|
+
|
61
|
+
|
62
|
+
def reset_password
|
63
|
+
before_reset_password
|
64
|
+
|
65
|
+
unless verify_recaptcha
|
66
|
+
flash[:error] = "You are not human! Please try again."
|
67
|
+
render :action=>"forgot_password"
|
68
|
+
return
|
69
|
+
end
|
70
|
+
|
71
|
+
@email = params[:email]
|
72
|
+
unless User.email_is_valid? @email
|
73
|
+
flash[:error] = "You must enter a valid email."
|
74
|
+
render :action=>"forgot_password"
|
75
|
+
return
|
76
|
+
end
|
77
|
+
|
78
|
+
@user = ::User.find_by_email(@email)
|
79
|
+
unless @user
|
80
|
+
flash[:error] = "Email not found."
|
81
|
+
render :action=>"forgot_password"
|
82
|
+
return
|
83
|
+
end
|
84
|
+
|
85
|
+
@newpass = random_string(8)
|
86
|
+
|
87
|
+
@user.password = @newpass
|
88
|
+
@user.save(:dirty=>true)
|
89
|
+
|
90
|
+
flash[:success] = "Password reset. You should receive an email shortly with a new password."
|
91
|
+
redirect_to :action=>"new"
|
92
|
+
|
93
|
+
after_reset_password
|
94
|
+
end
|
95
|
+
|
96
|
+
def before_reset_password
|
97
|
+
|
98
|
+
end
|
99
|
+
|
100
|
+
# This is a great spot to send an email with the new password (the only spot actually).
|
101
|
+
def after_reset_password
|
102
|
+
|
103
|
+
end
|
104
|
+
|
105
|
+
def destroy
|
106
|
+
logout
|
107
|
+
end
|
108
|
+
|
109
|
+
def logout
|
110
|
+
@current_user = nil
|
111
|
+
reset_session
|
112
|
+
flash[:info] = "You have been logged out."
|
113
|
+
redirect_to('/')
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
@@ -0,0 +1,206 @@
|
|
1
|
+
require 'aws'
|
2
|
+
require 'simple_record'
|
3
|
+
|
4
|
+
module Appoxy
|
5
|
+
module Sessions
|
6
|
+
module Shareable
|
7
|
+
|
8
|
+
# Call this method on your Sharable object to share it with the person.
|
9
|
+
# returns: a hash with :user (the user that the item was shared with), :ac (activation code that should be sent to the user)
|
10
|
+
# or false if couldn't be shared.
|
11
|
+
# You can check for errors by looking at the errors array of the object.
|
12
|
+
# Eg:
|
13
|
+
# if my_ob.share_with(x)
|
14
|
+
# # all good
|
15
|
+
# Mail the user a link that contains user_id and ac, this gem will take care of the rest.
|
16
|
+
# else
|
17
|
+
# # not all good, check errors
|
18
|
+
# errors = my_ob.errors
|
19
|
+
# end
|
20
|
+
|
21
|
+
def share_with(email, access_rights={}, options={})
|
22
|
+
|
23
|
+
access_rights = {} if access_rights.nil?
|
24
|
+
|
25
|
+
@email = email.strip
|
26
|
+
|
27
|
+
if @email == self.user.email
|
28
|
+
self.errors.add_to_base("User already owns this item.")
|
29
|
+
return false
|
30
|
+
end
|
31
|
+
|
32
|
+
user = ::User.find_by_email(@email)
|
33
|
+
if user.nil?
|
34
|
+
# lets create the user and send them an invite.
|
35
|
+
user = ::User.new(:email=>@email, :status=>"invited")
|
36
|
+
user.set_activation_code # todo: this shouldn't be on user anymore
|
37
|
+
if user.save
|
38
|
+
|
39
|
+
else
|
40
|
+
self.errors = user.errors
|
41
|
+
return false
|
42
|
+
end
|
43
|
+
end
|
44
|
+
activation_code = user.activation_code
|
45
|
+
|
46
|
+
# check if exists
|
47
|
+
share_domain = self.share_domain
|
48
|
+
item_id_name = self.item_id_name
|
49
|
+
# puts 'share_domain = ' + share_domain.inspect
|
50
|
+
@sdb = SimpleRecord::Base.connection
|
51
|
+
# @shared_with = share_class.find(:first, :conditions=>["user_id = ? and item_id = ?", user.id, @item.id])
|
52
|
+
@project_user = Shareable.get_results(:first, ["select * from #{share_domain} where user_id=? and #{item_id_name} = ?", user.id, self.id])
|
53
|
+
puts 'sharing user=' + @project_user.inspect
|
54
|
+
unless @project_user.nil?
|
55
|
+
self.errors.add_to_base("This item is already shared with #{email}.")
|
56
|
+
return false
|
57
|
+
end
|
58
|
+
|
59
|
+
now = Time.now
|
60
|
+
id = share_id(user)
|
61
|
+
@sdb.put_attributes(share_domain, id, {:new_share=>true,
|
62
|
+
:id=>id,
|
63
|
+
:created=>SimpleRecord::Translations.pad_and_offset(now),
|
64
|
+
:updated=>SimpleRecord::Translations.pad_and_offset(now),
|
65
|
+
:user_id => user.id,
|
66
|
+
:activation_code=>activation_code,
|
67
|
+
:status=>"invited",
|
68
|
+
item_id_name => self.id}.merge(access_rights),
|
69
|
+
true,
|
70
|
+
:create_domain=>true)
|
71
|
+
|
72
|
+
# ret = {
|
73
|
+
# :user=>user,
|
74
|
+
# :ac=>activation_code
|
75
|
+
# }
|
76
|
+
# return ret
|
77
|
+
return user
|
78
|
+
|
79
|
+
end
|
80
|
+
|
81
|
+
def item_id_name
|
82
|
+
return self.class.name.foreign_key
|
83
|
+
end
|
84
|
+
|
85
|
+
def common_attributes
|
86
|
+
["new_share", "id", "created", "updated", "user_id", item_id_name]
|
87
|
+
end
|
88
|
+
|
89
|
+
# Returns a list of users that this item is shared with.
|
90
|
+
def shared_with
|
91
|
+
project_users = Shareable.get_results(:all, ["select * from #{share_domain} where #{item_id_name} = ?", self.id])
|
92
|
+
user_ids = []
|
93
|
+
options_hash = {}
|
94
|
+
project_users.each do |puhash|
|
95
|
+
puhash.each_pair do |k, v|
|
96
|
+
puhash[k] = v[0]
|
97
|
+
end
|
98
|
+
puts 'puhash=' + puhash.inspect
|
99
|
+
user_ids << puhash["user_id"]
|
100
|
+
options_hash[puhash["user_id"]] = puhash
|
101
|
+
end
|
102
|
+
ret = ::User.find(:all, :conditions=>["id in ('#{user_ids.join("','")}')"]).collect do |u|
|
103
|
+
def u.share_options=(options=nil)
|
104
|
+
instance_variable_set(:@share_options, options)
|
105
|
+
end
|
106
|
+
|
107
|
+
def u.share_options
|
108
|
+
instance_variable_get(:@share_options)
|
109
|
+
end
|
110
|
+
|
111
|
+
u.share_options=options_hash[u.id]
|
112
|
+
u
|
113
|
+
end
|
114
|
+
ret
|
115
|
+
end
|
116
|
+
|
117
|
+
# this unshares by the
|
118
|
+
def unshare_by_id(id)
|
119
|
+
# @project_user = ProjectUser.find(params[:pu_id])
|
120
|
+
# @project_user.delete
|
121
|
+
# puts 'unsharing ' + id.to_s
|
122
|
+
@sdb = SimpleRecord::Base.connection
|
123
|
+
puts "delete_attributes=" + @sdb.delete_attributes(share_domain, id.to_s).inspect
|
124
|
+
# puts 'deleted?'
|
125
|
+
end
|
126
|
+
|
127
|
+
# Unshare by user.
|
128
|
+
def unshare(user)
|
129
|
+
@sdb = SimpleRecord::Base.connection
|
130
|
+
@sdb.delete_attributes(share_domain, share_id(user))
|
131
|
+
# @project_user = Shareable.get_results(:first, ["select * from #{share_domain} where user_id=? and #{item_id_name} = ?", user.id, self.id])
|
132
|
+
# @project_user.each do |pu|
|
133
|
+
# @sdb.delete_attributes(share_domain, pu["id"])
|
134
|
+
# end
|
135
|
+
end
|
136
|
+
|
137
|
+
def update_sharing_options(user, options={})
|
138
|
+
options={} if options.nil?
|
139
|
+
# puts 'options=' + ({ :updated=>Time.now }.merge(options)).inspect
|
140
|
+
@sdb = SimpleRecord::Base.connection
|
141
|
+
@project_user = Shareable.get_results(:first, ["select * from #{share_domain} where user_id=? and #{item_id_name} = ?", user.id, self.id])
|
142
|
+
# compare values
|
143
|
+
to_delete = []
|
144
|
+
@project_user.each_pair do |k, v|
|
145
|
+
if !common_attributes.include?(k) && !options.include?(k)
|
146
|
+
to_delete << k
|
147
|
+
end
|
148
|
+
end
|
149
|
+
if to_delete.size > 0
|
150
|
+
puts 'to_delete=' + to_delete.inspect
|
151
|
+
@sdb.delete_attributes(share_domain, share_id(user), to_delete)
|
152
|
+
end
|
153
|
+
@sdb.put_attributes(share_domain, share_id(user), {:updated=>Time.now}.merge(options), true)
|
154
|
+
|
155
|
+
end
|
156
|
+
|
157
|
+
def share_id(user)
|
158
|
+
"#{self.id}_#{user.id}"
|
159
|
+
end
|
160
|
+
|
161
|
+
def share_domain
|
162
|
+
# puts 'instance share_domain'
|
163
|
+
ret = self.class.name + "User"
|
164
|
+
# puts 'SHARE_NAME=' + ret
|
165
|
+
ret = ret.tableize
|
166
|
+
# puts 'ret=' + ret
|
167
|
+
ret
|
168
|
+
end
|
169
|
+
|
170
|
+
|
171
|
+
def self.get_results(which, q)
|
172
|
+
@sdb = SimpleRecord::Base.connection
|
173
|
+
next_token = nil
|
174
|
+
ret = []
|
175
|
+
begin
|
176
|
+
begin
|
177
|
+
response = @sdb.select(q, next_token)
|
178
|
+
rs = response[:items]
|
179
|
+
rs.each_with_index do |i, index|
|
180
|
+
puts 'i=' + i.inspect
|
181
|
+
i.each_key do |k|
|
182
|
+
puts 'key=' + k.inspect
|
183
|
+
if which == :first
|
184
|
+
return i[k].update("id"=>k)
|
185
|
+
end
|
186
|
+
ret << i[k]
|
187
|
+
end
|
188
|
+
# break if index > 100
|
189
|
+
end
|
190
|
+
next_token = response[:next_token]
|
191
|
+
end until next_token.nil?
|
192
|
+
rescue Aws::AwsError, Aws::ActiveSdb::ActiveSdbError
|
193
|
+
if ($!.message().index("NoSuchDomain") != nil)
|
194
|
+
puts 'NO SUCH DOMAIN!!!'
|
195
|
+
# this is ok
|
196
|
+
else
|
197
|
+
raise $!
|
198
|
+
end
|
199
|
+
end
|
200
|
+
which == :first ? nil : ret
|
201
|
+
end
|
202
|
+
|
203
|
+
end
|
204
|
+
end
|
205
|
+
end
|
206
|
+
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module Appoxy
|
2
|
+
|
3
|
+
module Sessions
|
4
|
+
|
5
|
+
class User < SimpleRecord::Base
|
6
|
+
|
7
|
+
def self.included(base)
|
8
|
+
puts self.name + " included in " + base.name
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
has_strings :email,
|
13
|
+
{:name => :password, :hashed=>true},
|
14
|
+
:first_name,
|
15
|
+
:last_name,
|
16
|
+
:remember_me,
|
17
|
+
:activation_code,
|
18
|
+
:status # invited, active
|
19
|
+
|
20
|
+
has_dates :last_login
|
21
|
+
|
22
|
+
|
23
|
+
def validate
|
24
|
+
errors.add("email", "is not valid") unless User.email_is_valid?(email)
|
25
|
+
|
26
|
+
if status == "invited"
|
27
|
+
# doesn't need password
|
28
|
+
else
|
29
|
+
errors.add("password", "must be at least 6 characters long.") if password.blank?
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
def self.email_is_valid?(email)
|
35
|
+
return email.present? && email =~ /^([^@\s]+)@((?:[-a-z0-9]+\.)+[a-z]{2,})$/i
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
def is_active?
|
40
|
+
status == "active"
|
41
|
+
end
|
42
|
+
|
43
|
+
|
44
|
+
|
45
|
+
def set_activation_code
|
46
|
+
self.activation_code=Digest::SHA1.hexdigest(email.to_s+Time.now.to_s)
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
def activate!
|
51
|
+
self.activation_code=nil
|
52
|
+
self.status = "active"
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
|
57
|
+
def authenticate(password)
|
58
|
+
|
59
|
+
return nil if attributes["password"].blank? # if the user has no password (will this happen? maybe for invites...)
|
60
|
+
|
61
|
+
# This is a normal unencrypted password, temporary
|
62
|
+
if attributes["password"][0].length < 100
|
63
|
+
self.password = attributes["password"][0]
|
64
|
+
self.save
|
65
|
+
end
|
66
|
+
|
67
|
+
(self.password == password) ? self : nil
|
68
|
+
end
|
69
|
+
|
70
|
+
|
71
|
+
end
|
72
|
+
|
73
|
+
end
|
74
|
+
|
75
|
+
end
|
76
|
+
|
@@ -0,0 +1,122 @@
|
|
1
|
+
module Appoxy
|
2
|
+
|
3
|
+
module Sessions
|
4
|
+
module UsersController
|
5
|
+
|
6
|
+
|
7
|
+
def new
|
8
|
+
before_new
|
9
|
+
if params[:id]
|
10
|
+
@user = ::User.find params[:id]
|
11
|
+
else
|
12
|
+
@user = ::User.new
|
13
|
+
@user.email = params[:email] if params[:email]
|
14
|
+
end
|
15
|
+
@user.activation_code = params[:ac] if params[:ac]
|
16
|
+
after_new
|
17
|
+
end
|
18
|
+
|
19
|
+
def before_new
|
20
|
+
|
21
|
+
end
|
22
|
+
|
23
|
+
def after_new
|
24
|
+
|
25
|
+
end
|
26
|
+
|
27
|
+
def create
|
28
|
+
|
29
|
+
before_create
|
30
|
+
|
31
|
+
@user = ::User.new(params[:user])
|
32
|
+
|
33
|
+
if @user.password != params[:password_confirmation]
|
34
|
+
flash[:error] = "Confirmation password does not match. Please try again."
|
35
|
+
render :action=>"new"
|
36
|
+
return
|
37
|
+
end
|
38
|
+
|
39
|
+
if params[:user][:password].length < 6
|
40
|
+
flash[:error] = "Password can not be less than 6 characters."
|
41
|
+
render :action=>"new"
|
42
|
+
return
|
43
|
+
end
|
44
|
+
|
45
|
+
existing_user = ::User.find_by_email(@user.email)
|
46
|
+
|
47
|
+
if existing_user
|
48
|
+
if params[:ac]
|
49
|
+
|
50
|
+
end
|
51
|
+
# todo: remove activation_code on user
|
52
|
+
if @user.activation_code.present?
|
53
|
+
# hasn't logged in yet, probably invited, need to check access key
|
54
|
+
if existing_user.activation_code == @user.activation_code
|
55
|
+
existing_user.activate!
|
56
|
+
existing_user.password = @user.password
|
57
|
+
@user = existing_user
|
58
|
+
end
|
59
|
+
else
|
60
|
+
flash[:error] = "The email you entered already exists in our system. You might want to try logging in if you already have an account."
|
61
|
+
render :action=>"new"
|
62
|
+
return
|
63
|
+
end
|
64
|
+
else
|
65
|
+
@user.status = "active"
|
66
|
+
end
|
67
|
+
|
68
|
+
before_save_in_create
|
69
|
+
if @user.save
|
70
|
+
self.current_user = @user
|
71
|
+
flash[:success] = "Your account was created successfully."
|
72
|
+
after_save_in_create
|
73
|
+
after_create
|
74
|
+
else
|
75
|
+
render :action => "new"
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
|
80
|
+
def before_create
|
81
|
+
|
82
|
+
end
|
83
|
+
|
84
|
+
def before_save_in_create
|
85
|
+
|
86
|
+
end
|
87
|
+
|
88
|
+
def after_save_in_create
|
89
|
+
|
90
|
+
end
|
91
|
+
|
92
|
+
def after_create
|
93
|
+
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
# Usually a user gets here via an activation link in email.
|
98
|
+
def activate
|
99
|
+
logout_keeping_session!
|
100
|
+
@user = ::User.find_by_activation_code(params[:ac]) unless params[:ac].blank?
|
101
|
+
case
|
102
|
+
when (!params[:ac].blank?) && @user && !@user.is_active?
|
103
|
+
flash[:info] = "Account activated. please login."
|
104
|
+
@user.activate!
|
105
|
+
redirect_to login_url
|
106
|
+
when params[:ac].blank?
|
107
|
+
flash[:error] = "The activation code was missing. Please follow the URL from your email."
|
108
|
+
redirect_to(root_url)
|
109
|
+
else
|
110
|
+
flash[:error] = "We couldn't find a user with that activation code -- check your email? Or maybe you've already activated -- try signing in."
|
111
|
+
redirect_to(root_url)
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
end
|
122
|
+
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Appoxy
|
2
|
+
|
3
|
+
module UI
|
4
|
+
|
5
|
+
module ApplicationHelper
|
6
|
+
|
7
|
+
def self.included(base)
|
8
|
+
# puts self.class.name + " included in " + base.class.name
|
9
|
+
end
|
10
|
+
|
11
|
+
|
12
|
+
def current_url
|
13
|
+
request.url
|
14
|
+
end
|
15
|
+
|
16
|
+
def flash_messages
|
17
|
+
s = ""
|
18
|
+
flash.each_pair do |type, msg|
|
19
|
+
if msg.is_a?(Array)
|
20
|
+
msg.each do |m|
|
21
|
+
s << content_tag(:div, m, :class => type)
|
22
|
+
end
|
23
|
+
else
|
24
|
+
s << content_tag(:div, msg, :class => type)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
s.html_safe
|
28
|
+
end
|
29
|
+
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
|
metadata
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: appoxy_rails
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 6
|
9
|
+
version: 0.0.6
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Travis Reeder
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-12-23 00:00:00 -08:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: rest-client
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
segments:
|
29
|
+
- 0
|
30
|
+
version: "0"
|
31
|
+
type: :runtime
|
32
|
+
version_requirements: *id001
|
33
|
+
description: Appoxy API Helper gem description...
|
34
|
+
email: travis@appoxy.com
|
35
|
+
executables: []
|
36
|
+
|
37
|
+
extensions: []
|
38
|
+
|
39
|
+
extra_rdoc_files:
|
40
|
+
- README.markdown
|
41
|
+
files:
|
42
|
+
- lib/api/api_controller.rb
|
43
|
+
- lib/api/client.rb
|
44
|
+
- lib/api/client_helper.rb
|
45
|
+
- lib/api/signatures.rb
|
46
|
+
- lib/appoxy_api.rb
|
47
|
+
- lib/appoxy_sessions.rb
|
48
|
+
- lib/appoxy_ui.rb
|
49
|
+
- lib/sessions/application_controller.rb
|
50
|
+
- lib/sessions/sessions_controller.rb
|
51
|
+
- lib/sessions/shareable.rb
|
52
|
+
- lib/sessions/user.rb
|
53
|
+
- lib/sessions/users_controller.rb
|
54
|
+
- lib/ui/application_helper.rb
|
55
|
+
- README.markdown
|
56
|
+
has_rdoc: true
|
57
|
+
homepage: http://www.appoxy.com
|
58
|
+
licenses: []
|
59
|
+
|
60
|
+
post_install_message:
|
61
|
+
rdoc_options: []
|
62
|
+
|
63
|
+
require_paths:
|
64
|
+
- lib
|
65
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
segments:
|
71
|
+
- 0
|
72
|
+
version: "0"
|
73
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
|
+
none: false
|
75
|
+
requirements:
|
76
|
+
- - ">="
|
77
|
+
- !ruby/object:Gem::Version
|
78
|
+
segments:
|
79
|
+
- 0
|
80
|
+
version: "0"
|
81
|
+
requirements: []
|
82
|
+
|
83
|
+
rubyforge_project:
|
84
|
+
rubygems_version: 1.3.7
|
85
|
+
signing_key:
|
86
|
+
specification_version: 3
|
87
|
+
summary: Appoxy Rails Helper gem
|
88
|
+
test_files: []
|
89
|
+
|