redsafe 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/.document +5 -0
- data/.gitignore +5 -0
- data/GemcutterInstructions.rdoc +74 -0
- data/LICENSE +20 -0
- data/README.rdoc +13 -0
- data/Rakefile +30 -0
- data/lib/models/scarlet_letters.rb +90 -0
- data/lib/models/sl_aah.rb +50 -0
- data/lib/models/sl_user.rb +119 -0
- data/lib/redsafe/version.rb +9 -0
- data/lib/redsafe.rb +268 -0
- data/lib/views/edit.haml +42 -0
- data/lib/views/index.haml +30 -0
- data/lib/views/login.haml +21 -0
- data/lib/views/show.haml +10 -0
- data/lib/views/signup.haml +25 -0
- data/test/redsafe_test.rb +7 -0
- data/test/test_helper.rb +10 -0
- metadata +133 -0
data/.document
ADDED
@@ -0,0 +1,74 @@
|
|
1
|
+
= RedSafe Gemcutter Setup
|
2
|
+
|
3
|
+
Gem Cutter set up was more time consuming than I had anticipated. Realized that I needed: task "default" => ["test"] inside the Rakefile to have rake command work for me. Additionally, I needed to use: gem cert before I could upload to Gemcutter.
|
4
|
+
|
5
|
+
== Notes on the Red Safe Gem Creation
|
6
|
+
|
7
|
+
* 1) rake
|
8
|
+
(Needed to set a default for the task.)
|
9
|
+
|
10
|
+
Added default task to Rakefile
|
11
|
+
task "default" => ["test"]
|
12
|
+
|
13
|
+
* 2) rake gemspec
|
14
|
+
(Worked for me first time.)
|
15
|
+
|
16
|
+
Generated: redsafe.gemspec
|
17
|
+
redsafe.gemspec is valid.
|
18
|
+
|
19
|
+
* 3) rdoc
|
20
|
+
(Created documentation for the redsafe project.)
|
21
|
+
|
22
|
+
redsafe.rb: mm.m.......c...
|
23
|
+
sl_user.rb: c.....cc....
|
24
|
+
sl_aah.rb: m.m.....m..
|
25
|
+
scarlet_letters.rb: c........
|
26
|
+
version.rb: cm
|
27
|
+
Generating HTML...
|
28
|
+
|
29
|
+
Files: 5
|
30
|
+
Classes: 6
|
31
|
+
Modules: 7
|
32
|
+
Methods: 36
|
33
|
+
Elapsed: 0.593s
|
34
|
+
|
35
|
+
* 4) gem build redsafe.gemspec
|
36
|
+
(Was able to build after I took author name "Ruby Shot" from an array structure and turned it into a string by removing the brackets, [ ].
|
37
|
+
|
38
|
+
# gem build redsafe.gemspec
|
39
|
+
ERROR: While executing gem ... (Gem::InvalidSpecificationException)
|
40
|
+
authors must be Array of Strings
|
41
|
+
|
42
|
+
|
43
|
+
* 5) gem push redsafe.gem
|
44
|
+
(As mentioned above, the gem certification was not set. Thus, I couldn't get an upload to Gemcutter.)
|
45
|
+
|
46
|
+
Your api key has been stored in ~/.gem/credentials
|
47
|
+
Pushing gem to Gemcutter...
|
48
|
+
ERROR: While executing gem ... (Errno::ENOENT)
|
49
|
+
No such file or directory - redsafe.gem
|
50
|
+
|
51
|
+
|
52
|
+
* 6) gem cert --build you@yourmail.com
|
53
|
+
(Use this command to create the certification for Gemcutter. I used my email address. I also moved the Public Cert and the Private Key to a safer location.)
|
54
|
+
|
55
|
+
Public Cert: gem-public_cert.pem
|
56
|
+
Private Key: gem-private_key.pem
|
57
|
+
Don't forget to move the key file to somewhere private...
|
58
|
+
|
59
|
+
|
60
|
+
* 7)gem push redsafe-0.1.1.gem
|
61
|
+
(I was successful when I used the above command. Used the Gemcutter search and verified that redsafe was being hosted on Gemcutter. Didn't test it, but left it in place.)
|
62
|
+
|
63
|
+
Pushing gem to Gemcutter...
|
64
|
+
Successfully registered gem: redsafe (0.1.1)
|
65
|
+
|
66
|
+
== Copyright
|
67
|
+
|
68
|
+
Copyright (c) 2010 Ruby Shot. See LICENSE for details.
|
69
|
+
|
70
|
+
|
71
|
+
|
72
|
+
|
73
|
+
|
74
|
+
|
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Ruby Shot
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
= RedSafe
|
2
|
+
|
3
|
+
The Red Safe Project deals with the creation of a gem. The gem's function is to streamline access to various websites through a connection consolidation of procedures.
|
4
|
+
|
5
|
+
== Notes on the Red Safe Project
|
6
|
+
* This Project's focus is learning based.
|
7
|
+
* It is designed to function with the appengine jruby.
|
8
|
+
* Clone it for your learning needs.
|
9
|
+
* git clone git@github.com:rubyshot/redsafe.git
|
10
|
+
|
11
|
+
== Copyright
|
12
|
+
|
13
|
+
Copyright (c) 2010 Ruby Shot. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
task "default" => ["test"]
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
require 'lib/redsafe/version'
|
7
|
+
Jeweler::Tasks.new do |gem|
|
8
|
+
gem.name = "redsafe"
|
9
|
+
gem.version = Redsafe::Version::STRING
|
10
|
+
gem.description = "Red Safe is a conveyor belt to get your web-based project on a fast roll."
|
11
|
+
gem.summary = "This is a gem tool which simplifies signup functionality using various web services for connection credentials."
|
12
|
+
gem.homepage = "http://github.com/rubyshot/redsafe"
|
13
|
+
gem.author = "Ruby Shot"
|
14
|
+
gem.email = "domochoice(at)yahoo:com"
|
15
|
+
gem.add_development_dependency "sinatra"
|
16
|
+
gem.add_development_dependency "dm-core"
|
17
|
+
gem.add_development_dependency "dm-validations"
|
18
|
+
gem.add_development_dependency "dm-timestamps"
|
19
|
+
gem.add_development_dependency "date"
|
20
|
+
gem.add_development_dependency "time"
|
21
|
+
end
|
22
|
+
rescue LoadError
|
23
|
+
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
24
|
+
end
|
25
|
+
|
26
|
+
|
27
|
+
|
28
|
+
|
29
|
+
|
30
|
+
|
@@ -0,0 +1,90 @@
|
|
1
|
+
if Object.const_defined?("DataMapper")
|
2
|
+
#require 'dm-core'
|
3
|
+
require 'dm-timestamps'
|
4
|
+
require 'dm-validations'
|
5
|
+
require 'date'
|
6
|
+
require 'time'
|
7
|
+
|
8
|
+
require Pathname(__FILE__).dirname.expand_path + "sl_user.rb"
|
9
|
+
require Pathname(__FILE__).dirname.expand_path + "sl_aah.rb"
|
10
|
+
|
11
|
+
end
|
12
|
+
|
13
|
+
class User
|
14
|
+
if Object.const_defined?("DataMapper")
|
15
|
+
include SlAah
|
16
|
+
else
|
17
|
+
throw "'dm-core' required for red safe "
|
18
|
+
end
|
19
|
+
|
20
|
+
def initialize(interfacing_class_instance)
|
21
|
+
@instance = interfacing_class_instance
|
22
|
+
end
|
23
|
+
|
24
|
+
def id
|
25
|
+
@instance.id
|
26
|
+
end
|
27
|
+
|
28
|
+
def self.authenticate(email, pass)
|
29
|
+
current_user = get(:email => email)
|
30
|
+
return nil if current_user.nil?
|
31
|
+
return current_user if User.encrypt(pass, current_user.salt) == current_user.hashed_password
|
32
|
+
nil
|
33
|
+
end
|
34
|
+
|
35
|
+
protected
|
36
|
+
|
37
|
+
def self.encrypt(pass, salt)
|
38
|
+
Digest::SHA1.hexdigest(pass+salt)
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.random_string(len)
|
42
|
+
#generate a random password consisting of strings and digits
|
43
|
+
chars = ("a".."z").to_a + ("A".."Z").to_a + ("0".."9").to_a
|
44
|
+
newpass = ""
|
45
|
+
1.upto(len) { |i| newpass << chars[rand(chars.size-1)] }
|
46
|
+
return newpass
|
47
|
+
end
|
48
|
+
|
49
|
+
#Created 3 actions and terminology thereof:
|
50
|
+
#1. sist: generates a string
|
51
|
+
#2. desist: receives the sist from an authorized server and breaks it apart
|
52
|
+
#3. resist: receives the desist string and reviews its integrity
|
53
|
+
|
54
|
+
def self.sist
|
55
|
+
const_set(TIME_FMT, '%Y-%m-%dT%H:%M:%SZ')
|
56
|
+
junk = self.random_string(6)
|
57
|
+
t = Time.now.getutc
|
58
|
+
time_str = t.strftime(TIME_FMT)
|
59
|
+
the_sist_str = time_str + junk
|
60
|
+
return the_sist_str
|
61
|
+
end
|
62
|
+
|
63
|
+
def self.desist( the_sist_str )
|
64
|
+
#"0000-00-00T00:00:00Z"
|
65
|
+
const_set(TIME_STR_LEN, 20 )
|
66
|
+
const_set(TIME_VALIDATOR,"/\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\dZ/")
|
67
|
+
timestamp_str = the_sist_str[0...TIME_STR_LEN]
|
68
|
+
raise ArgumentError if timestamp_str.size < TIME_STR_LEN
|
69
|
+
raise ArgumentError unless timestamp_str.match(TIME_VALIDATOR)
|
70
|
+
timestamp = Time.parse(timestamp_str).to_i
|
71
|
+
raise ArgumentError if ts < 0
|
72
|
+
return timestamp, the_sist_str[20..-1]
|
73
|
+
end
|
74
|
+
|
75
|
+
def self.resist(the_sist_str)
|
76
|
+
const_set(TIME_RANGE, 60*60*5)
|
77
|
+
timestamp, junk = self.desist(the_sist_str)
|
78
|
+
now = Time.now.to_i
|
79
|
+
start = now - TIME_RANGE
|
80
|
+
finish = now + TIME_RANGE
|
81
|
+
return true if (start <= timestamp and timestamp <= finish)
|
82
|
+
return false
|
83
|
+
end
|
84
|
+
|
85
|
+
|
86
|
+
|
87
|
+
end
|
88
|
+
|
89
|
+
|
90
|
+
|
@@ -0,0 +1,50 @@
|
|
1
|
+
module SlAah
|
2
|
+
def self.included(base)
|
3
|
+
base.extend ClassMethods
|
4
|
+
base.class_eval { include SlAah::InstanceMethods }
|
5
|
+
end
|
6
|
+
|
7
|
+
module ClassMethods
|
8
|
+
def all
|
9
|
+
result = SlUser.all
|
10
|
+
result.collect {|instance| self.new instance}
|
11
|
+
end
|
12
|
+
|
13
|
+
def get(hash)
|
14
|
+
if user = SlUser.first(hash)
|
15
|
+
self.new user
|
16
|
+
else
|
17
|
+
nil
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def set(attributes)
|
22
|
+
user = SlUser.new attributes
|
23
|
+
user.save
|
24
|
+
user
|
25
|
+
end
|
26
|
+
|
27
|
+
def set!(attributes)
|
28
|
+
user = SlUser.new attributes
|
29
|
+
user.save!
|
30
|
+
user
|
31
|
+
end
|
32
|
+
|
33
|
+
def delete(pk)
|
34
|
+
user = User.first(:id => pk)
|
35
|
+
user.destroy
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
module InstanceMethods
|
40
|
+
def update(attributes)
|
41
|
+
@instance.update_attributes attributes
|
42
|
+
@instance.save
|
43
|
+
end
|
44
|
+
|
45
|
+
def method_missing(meth, *args, &block)
|
46
|
+
#cool I just found out * on an array turns the array into a list of args for a function
|
47
|
+
@instance.send(meth, *args, &block)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
@@ -0,0 +1,119 @@
|
|
1
|
+
class SlUser
|
2
|
+
include DataMapper::Resource
|
3
|
+
|
4
|
+
property :id, Serial
|
5
|
+
property :email, String, :length => (5..40), :unique => true, :format => :email_address
|
6
|
+
property :hashed_password, String
|
7
|
+
property :salt, String
|
8
|
+
property :created_at, DateTime
|
9
|
+
property :permission_level, Integer, :default => 1
|
10
|
+
property :nickname, String, :length => 255
|
11
|
+
property :identifier, String, :length => 255
|
12
|
+
property :photo_url, String, :length => 255
|
13
|
+
|
14
|
+
has n, :oohs
|
15
|
+
has n, :direct_messages, :model => "Ooh"
|
16
|
+
has n, :relationships
|
17
|
+
has n, :followers, :through => :relationships, :model => "SlUser", :child_key => [:SlUser_id]
|
18
|
+
has n, :follows, :through => :relationships, :model => "SlUser", :remote_name => :SlUser, :child_key => [:follower_id]
|
19
|
+
if Sinatra.const_defined?('FacebookObject')
|
20
|
+
property :fb_uid, String
|
21
|
+
end
|
22
|
+
|
23
|
+
attr_accessor :password, :password_confirmation
|
24
|
+
#protected equievelant? :protected => true doesn't exist in dm 0.10.0
|
25
|
+
#protected :id, :salt
|
26
|
+
#doesn't behave correctly, I'm not even sure why I did this.
|
27
|
+
|
28
|
+
validates_present :password_confirmation, :unless => Proc.new { |t| t.hashed_password }
|
29
|
+
validates_present :password, :unless => Proc.new { |t| t.hashed_password }
|
30
|
+
validates_is_confirmed :password
|
31
|
+
|
32
|
+
def password=(pass)
|
33
|
+
@password = pass
|
34
|
+
self.salt = SlUser.random_string(10) if !self.salt
|
35
|
+
self.hashed_password = SlUser.encrypt(@password, self.salt)
|
36
|
+
end
|
37
|
+
|
38
|
+
def admin?
|
39
|
+
self.permission_level == -1 || self.id == 1
|
40
|
+
end
|
41
|
+
|
42
|
+
def site_admin?
|
43
|
+
self.id == 1
|
44
|
+
end
|
45
|
+
|
46
|
+
def displayed_oohs
|
47
|
+
oohs = []
|
48
|
+
oohs += self.oohs.all(:recipient_id => nil, :limit => 10, :order => [:created_at.desc]) # don't show direct messsages
|
49
|
+
self.follows.each do |follows| oohs += follows.oohs.all(:recipient_id => nil, :limit => 10, :order => [:created_at.desc]) end if @myself == @user
|
50
|
+
oohs.sort! { |x,y| y.created_at <=> x.created_at }
|
51
|
+
oohs[0..10]
|
52
|
+
end
|
53
|
+
|
54
|
+
protected
|
55
|
+
|
56
|
+
def method_missing(m, *args)
|
57
|
+
return false
|
58
|
+
end
|
59
|
+
end
|
60
|
+
class Relationship
|
61
|
+
include DataMapper::Resource
|
62
|
+
|
63
|
+
property :SlUser_id, Integer, :key => true
|
64
|
+
property :follower_id, Integer, :key => true
|
65
|
+
belongs_to :SlUser, :child_key => [:SlUser_id]
|
66
|
+
belongs_to :follower, :model => "SlUser", :child_key => [:follower_id]
|
67
|
+
end
|
68
|
+
|
69
|
+
class Ooh
|
70
|
+
include DataMapper::Resource
|
71
|
+
|
72
|
+
property :id, Serial
|
73
|
+
property :text, String, :length => 140
|
74
|
+
property :created_at, DateTime
|
75
|
+
belongs_to :recipient, :model => "SlUser", :child_key => [:recipient_id]
|
76
|
+
belongs_to :SlUser
|
77
|
+
|
78
|
+
before :save do
|
79
|
+
case
|
80
|
+
when starts_with?('dm ')
|
81
|
+
process_dm
|
82
|
+
when starts_with?('follow ')
|
83
|
+
process_follow
|
84
|
+
else
|
85
|
+
process
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
# general scrubbing of an ooh
|
90
|
+
def process
|
91
|
+
# process url
|
92
|
+
urls = self.text.scan(URL_REGEXP)
|
93
|
+
urls.each { |url|
|
94
|
+
tiny_url = open("http://tinyurl.com/api-create.php?url=#{url[0]}") {|s| s.read}
|
95
|
+
self.text.sub!(url[0], "<a href='#{tiny_url}'>#{tiny_url}</a>")
|
96
|
+
}
|
97
|
+
# process @
|
98
|
+
ats = self.text.scan(AT_REGEXP)
|
99
|
+
ats.each { |at| self.text.sub!(at, "<a href='/#{at[2,at.length]}'>#{at}</a>") }
|
100
|
+
end
|
101
|
+
|
102
|
+
# process direct messages
|
103
|
+
def process_dm
|
104
|
+
self.recipient = SlUser.first(:email => self.text.split[1])
|
105
|
+
self.text = self.text.split[2..self.text.split.size].join(' ') # remove the first 2 words
|
106
|
+
process
|
107
|
+
end
|
108
|
+
|
109
|
+
# process follow commands
|
110
|
+
def process_follow
|
111
|
+
Relationship.create(:SlUser => SlUser.first(:email => self.text.split[1]), :follower => self.SlUser)
|
112
|
+
throw :halt # don't save
|
113
|
+
end
|
114
|
+
|
115
|
+
def starts_with?(prefix)
|
116
|
+
prefix = prefix.to_s
|
117
|
+
self.text[0, prefix.length] == prefix
|
118
|
+
end
|
119
|
+
end
|
data/lib/redsafe.rb
ADDED
@@ -0,0 +1,268 @@
|
|
1
|
+
require 'sinatra/base'
|
2
|
+
require 'pathname'
|
3
|
+
require Pathname(__FILE__).dirname.expand_path + "models/scarlet_letters"
|
4
|
+
|
5
|
+
module Sinatra
|
6
|
+
module RedSlash
|
7
|
+
def self.registered(app)
|
8
|
+
#INVESTIGATE
|
9
|
+
#the possibility of sinatra having an array of view_paths to load from
|
10
|
+
#PROBLEM
|
11
|
+
#sinatra 9.1.1 doesn't have multiple view capability anywhere
|
12
|
+
#so to get around I have to do it totally manually by
|
13
|
+
#loading the view from this path into a string and rendering it
|
14
|
+
set :red_slash_view_path, Pathname(__FILE__).dirname.expand_path + "views/"
|
15
|
+
|
16
|
+
get '/users' do
|
17
|
+
login_required
|
18
|
+
redirect "/" unless current_user.admin?
|
19
|
+
|
20
|
+
@users = User.all
|
21
|
+
if @users != []
|
22
|
+
haml get_view_as_string("index.haml"), :layout => use_layout?
|
23
|
+
else
|
24
|
+
redirect '/signup'
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
get '/users/:id' do
|
29
|
+
login_required
|
30
|
+
|
31
|
+
@user = User.get(:id => params[:id])
|
32
|
+
haml get_view_as_string("show.haml"), :layout => use_layout?
|
33
|
+
end
|
34
|
+
|
35
|
+
#convenience for ajax but maybe entirely stupid and unnecesary
|
36
|
+
get '/logged_in' do
|
37
|
+
if session[:user]
|
38
|
+
"true"
|
39
|
+
else
|
40
|
+
"false"
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
get '/login' do
|
45
|
+
haml get_view_as_string("login.haml"), :layout => use_layout?
|
46
|
+
end
|
47
|
+
|
48
|
+
post '/login' do
|
49
|
+
if user = User.authenticate(params[:email], params[:password])
|
50
|
+
session[:user] = user.id
|
51
|
+
if session[:return_to]
|
52
|
+
redirect_url = session[:return_to]
|
53
|
+
session[:return_to] = false
|
54
|
+
redirect redirect_url
|
55
|
+
else
|
56
|
+
redirect '/'
|
57
|
+
end
|
58
|
+
else
|
59
|
+
redirect '/login'
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
get '/logout' do
|
64
|
+
session[:user] = nil
|
65
|
+
@message = "in case it weren't obvious, you've logged out"
|
66
|
+
redirect '/'
|
67
|
+
end
|
68
|
+
|
69
|
+
get '/signup' do
|
70
|
+
haml get_view_as_string("signup.haml"), :layout => use_layout?
|
71
|
+
end
|
72
|
+
|
73
|
+
post '/signup' do
|
74
|
+
@user = User.set(params[:user])
|
75
|
+
if @user
|
76
|
+
session[:user] = @user.id
|
77
|
+
redirect '/'
|
78
|
+
else
|
79
|
+
session[:flash] = "failure!"
|
80
|
+
redirect '/'
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
get '/users/:id/edit' do
|
85
|
+
login_required
|
86
|
+
redirect "/users" unless current_user.admin? || current_user.id.to_s == params[:id]
|
87
|
+
|
88
|
+
@user = User.get(:id => params[:id])
|
89
|
+
haml get_view_as_string("edit.haml"), :layout => use_layout?
|
90
|
+
end
|
91
|
+
|
92
|
+
post '/users/:id/edit' do
|
93
|
+
login_required
|
94
|
+
redirect "/users" unless current_user.admin? || current_user.id.to_s == params[:id]
|
95
|
+
|
96
|
+
user = User.get(:id => params[:id])
|
97
|
+
user_attributes = params[:user]
|
98
|
+
if params[:user][:password] == ""
|
99
|
+
user_attributes.delete("password")
|
100
|
+
user_attributes.delete("password_confirmation")
|
101
|
+
end
|
102
|
+
|
103
|
+
if user.update(user_attributes)
|
104
|
+
redirect '/'
|
105
|
+
else
|
106
|
+
session[:notice] = 'whoops, looks like there were some problems with your updates'
|
107
|
+
redirect "/users/#{user.id}/edit"
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
get '/users/:id/delete' do
|
112
|
+
login_required
|
113
|
+
redirect "/users" unless current_user.admin? || current_user.id.to_s == params[:id]
|
114
|
+
|
115
|
+
if User.delete(params[:id])
|
116
|
+
session[:flash] = "way to go, you deleted a user"
|
117
|
+
else
|
118
|
+
session[:flash] = "deletion failed, for whatever reason"
|
119
|
+
end
|
120
|
+
redirect '/'
|
121
|
+
end
|
122
|
+
|
123
|
+
|
124
|
+
if Sinatra.const_defined?('FacebookObject')
|
125
|
+
get '/connect' do
|
126
|
+
if fb[:user]
|
127
|
+
if current_user.class != GuestUser
|
128
|
+
user = current_user
|
129
|
+
else
|
130
|
+
user = User.get(:fb_uid => fb[:user])
|
131
|
+
end
|
132
|
+
|
133
|
+
if user
|
134
|
+
if !user.fb_uid || user.fb_uid != fb[:user]
|
135
|
+
user.update :fb_uid => fb[:user]
|
136
|
+
end
|
137
|
+
session[:user] = user.id
|
138
|
+
else
|
139
|
+
user = User.set!(:fb_uid => fb[:user])
|
140
|
+
session[:user] = user.id
|
141
|
+
end
|
142
|
+
end
|
143
|
+
redirect '/'
|
144
|
+
end
|
145
|
+
|
146
|
+
get '/receiver' do
|
147
|
+
%[<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
|
148
|
+
<html xmlns="http://www.w3.org/1999/xhtml" >
|
149
|
+
<body>
|
150
|
+
<script src="http://static.ak.connect.facebook.com/js/api_lib/v0.4/XdCommReceiver.js" type="text/javascript"></script>
|
151
|
+
</body>
|
152
|
+
</html>]
|
153
|
+
end
|
154
|
+
end
|
155
|
+
end
|
156
|
+
end
|
157
|
+
|
158
|
+
module Helpers
|
159
|
+
def login_required
|
160
|
+
#not as efficient as checking the session. but this inits the fb_user if they are logged in
|
161
|
+
if current_user.class != GuestUser
|
162
|
+
return true
|
163
|
+
else
|
164
|
+
session[:return_to] = request.fullpath
|
165
|
+
redirect '/login'
|
166
|
+
return false
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def current_user
|
171
|
+
if session[:user]
|
172
|
+
User.get(:id => session[:user])
|
173
|
+
else
|
174
|
+
GuestUser.new
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
def logged_in?
|
179
|
+
!!session[:user]
|
180
|
+
end
|
181
|
+
|
182
|
+
def use_layout?
|
183
|
+
!request.xhr?
|
184
|
+
end
|
185
|
+
|
186
|
+
#BECAUSE sinatra 9.1.1 can't load views from different paths properly
|
187
|
+
def get_view_as_string(filename)
|
188
|
+
view = options.red_slash_view_path + filename
|
189
|
+
data = ""
|
190
|
+
f = File.open(view, "r")
|
191
|
+
f.each_line do |line|
|
192
|
+
data += line
|
193
|
+
end
|
194
|
+
return data
|
195
|
+
end
|
196
|
+
|
197
|
+
def render_login_logout(html_attributes = {:class => ""})
|
198
|
+
css_classes = html_attributes.delete(:class)
|
199
|
+
parameters = ''
|
200
|
+
html_attributes.each_pair do |attribute, value|
|
201
|
+
parameters += "#{attribute}=\"#{value}\" "
|
202
|
+
end
|
203
|
+
|
204
|
+
result = "<div id='sinatra-authentication-login-logout' >"
|
205
|
+
if logged_in?
|
206
|
+
logout_parameters = html_attributes
|
207
|
+
# a tad janky?
|
208
|
+
logout_parameters.delete(:rel)
|
209
|
+
result += "<a href='/users/#{current_user.id}/edit' class='#{css_classes} sinatra-authentication-edit' #{parameters}>Edit account</a> "
|
210
|
+
if Sinatra.const_defined?('FacebookObject')
|
211
|
+
if fb[:user]
|
212
|
+
result += "<a href='javascript:FB.Connect.logoutAndRedirect(\"/logout\");' class='#{css_classes} sinatra-authentication-logout' #{logout_parameters}>Logout</a>"
|
213
|
+
else
|
214
|
+
result += "<a href='/logout' class='#{css_classes} sinatra-authentication-logout' #{logout_parameters}>Logout</a>"
|
215
|
+
end
|
216
|
+
else
|
217
|
+
result += "<a href='/logout' class='#{css_classes} sinatra-authentication-logout' #{logout_parameters}>Logout</a>"
|
218
|
+
end
|
219
|
+
else
|
220
|
+
result += "<a href='/signup' class='#{css_classes} sinatra-authentication-signup' #{parameters}>Signup</a> "
|
221
|
+
result += "<a href='/login' class='#{css_classes} sinatra-authentication-login' #{parameters}>Login</a>"
|
222
|
+
end
|
223
|
+
|
224
|
+
result += "</div>"
|
225
|
+
end
|
226
|
+
|
227
|
+
if Sinatra.const_defined?('FacebookObject')
|
228
|
+
def render_facebook_connect_link(text = 'Login using facebook', options = {:size => 'small'})
|
229
|
+
if options[:size] == 'small'
|
230
|
+
size = 'Small'
|
231
|
+
elsif options[:size] == 'medium'
|
232
|
+
size = 'Medium'
|
233
|
+
elsif options[:size] == 'large'
|
234
|
+
size = 'Large'
|
235
|
+
elsif options[:size] == 'xlarge'
|
236
|
+
size = 'BigPun'
|
237
|
+
else
|
238
|
+
size = 'Small'
|
239
|
+
end
|
240
|
+
|
241
|
+
%[<a href="#" onclick="FB.Connect.requireSession(function(){document.location = '/connect';}); return false;" class="fbconnect_login_button FBConnectButton FBConnectButton_#{size}">
|
242
|
+
<span id="RES_ID_fb_login_text" class="FBConnectButton_Text">
|
243
|
+
#{text}
|
244
|
+
</span>
|
245
|
+
</a>]
|
246
|
+
end
|
247
|
+
end
|
248
|
+
end
|
249
|
+
|
250
|
+
register RedSlash
|
251
|
+
end
|
252
|
+
|
253
|
+
class GuestUser
|
254
|
+
def guest?
|
255
|
+
true
|
256
|
+
end
|
257
|
+
|
258
|
+
def permission_level
|
259
|
+
0
|
260
|
+
end
|
261
|
+
|
262
|
+
# current_user.admin? returns false. current_user.has_a_baby? returns false.
|
263
|
+
# (which is a bit of an assumption I suppose)
|
264
|
+
def method_missing(m, *args)
|
265
|
+
return false
|
266
|
+
end
|
267
|
+
end
|
268
|
+
|
data/lib/views/edit.haml
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
#redsafe
|
2
|
+
%h1
|
3
|
+
Edit
|
4
|
+
- if @user.id == current_user.id
|
5
|
+
account
|
6
|
+
- else
|
7
|
+
- if @user.email
|
8
|
+
= @user.email
|
9
|
+
- elsif @user.fb_uid
|
10
|
+
<fb:name uid=#{@user.fb_uid} linked='false' />
|
11
|
+
- else
|
12
|
+
account
|
13
|
+
%form{:action => "/users/#{@user.id}/edit", :method => "post"}
|
14
|
+
.field
|
15
|
+
.label
|
16
|
+
%label{:for => "user_email"} Email
|
17
|
+
%input{ :id => "user_email", :name => "user[email]", :size => 30, :type => "text", :value => @user.email }
|
18
|
+
.field
|
19
|
+
.label
|
20
|
+
%label{:for => "user_password"} New password
|
21
|
+
%input{ :id => "user_password", :name => "user[password]", :size => 30, :type => "password" }
|
22
|
+
.field
|
23
|
+
.label
|
24
|
+
%label{:for => "user_password_confirmation"} Confirm
|
25
|
+
%input{ :id => "user_password_confirmation", :name => "user[password_confirmation]", :size => 30, :type => "password" }
|
26
|
+
-# don't render permission field if admin and editing yourself so you don't shoot yourself in the foot
|
27
|
+
- if current_user.admin? && current_user.id != @user.id
|
28
|
+
.field
|
29
|
+
.label
|
30
|
+
%label{:for => 'permission_level'} Permission level
|
31
|
+
%select{ :id => "permission_level", :name => "user[permission_level]" }
|
32
|
+
%option{:value => -1, :selected => @user.admin?}
|
33
|
+
Admin
|
34
|
+
%option{:value => 1, :selected => @user.permission_level == 1}
|
35
|
+
Authenticated user
|
36
|
+
.buttons
|
37
|
+
%input{ :value => "Update", :type => "submit" }
|
38
|
+
- if Sinatra.const_defined?('FacebookObject')
|
39
|
+
- unless @user.fb_uid
|
40
|
+
|
|
41
|
+
= render_facebook_connect_link('Link account with Facebook')
|
42
|
+
|
@@ -0,0 +1,30 @@
|
|
1
|
+
#redsafe
|
2
|
+
%h1.page_title Users
|
3
|
+
%table
|
4
|
+
%tr
|
5
|
+
%th
|
6
|
+
- if current_user.admin?
|
7
|
+
%th permission level
|
8
|
+
- @users.each do |user|
|
9
|
+
%tr
|
10
|
+
%td
|
11
|
+
- if user.email
|
12
|
+
= user.email
|
13
|
+
- elsif user.fb_uid
|
14
|
+
<fb:name uid=#{user.fb_uid} />
|
15
|
+
- else
|
16
|
+
"user #{user.id}"
|
17
|
+
- if current_user.admin?
|
18
|
+
%td= user.permission_level
|
19
|
+
%td
|
20
|
+
%a{:href => "/users/#{user.id}"} show
|
21
|
+
- if current_user.admin?
|
22
|
+
%td
|
23
|
+
%a{:href => "/users/#{user.id}/edit"} edit
|
24
|
+
%td
|
25
|
+
-# this doesn't work for tk
|
26
|
+
- if !user.site_admin?
|
27
|
+
%a{:href => "/users/#{user.id}/delete", :onclick => "return confirm('you sure?')"} delete
|
28
|
+
- else
|
29
|
+
site admin
|
30
|
+
|
@@ -0,0 +1,21 @@
|
|
1
|
+
#redsafe
|
2
|
+
%h1.page_title Login
|
3
|
+
%form{:action => "/login", :method => "post"}
|
4
|
+
.field
|
5
|
+
.label
|
6
|
+
%label{:for => "user_email'"} Email
|
7
|
+
%input{:id => "user_email", :name => "email", :size => 30, :type => "text"}
|
8
|
+
.field
|
9
|
+
.label
|
10
|
+
%label{:for => "user_password"} Password
|
11
|
+
%input{:id => "user_password", :name => "password", :size => 30, :type => "password"}
|
12
|
+
.buttons
|
13
|
+
%input{:value => "login", :type => "submit"}
|
14
|
+
%a{:href => "/signup", :class => 'sinatra_authentication_link'}
|
15
|
+
Signup
|
16
|
+
- if Sinatra.const_defined?('FacebookObject')
|
17
|
+
.third_party_signup
|
18
|
+
%h3.section_title One click login:
|
19
|
+
.login_link.facebook_login
|
20
|
+
= render_facebook_connect_link('Login using facebook', :size => 'large')
|
21
|
+
|
data/lib/views/show.haml
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
#redsafe
|
2
|
+
%h1.page_title Signup
|
3
|
+
%form{:action => "/signup", :method => "post"}
|
4
|
+
.field
|
5
|
+
.label
|
6
|
+
%label{:for => "user_email"} Email
|
7
|
+
%input{ :id => "user_email", :name => "user[email]", :size => 30, :type => "text" }
|
8
|
+
.field
|
9
|
+
.label
|
10
|
+
%label{:for => "user_password"} Password
|
11
|
+
%input{ :id => "user_password", :name => "user[password]", :size => 30, :type => "password" }
|
12
|
+
.field
|
13
|
+
.label
|
14
|
+
%label{:for => "user_password_confirmation"} Confirm Password
|
15
|
+
%input{ :id => "user_password_confirmation", :name => "user[password_confirmation]", :size => 30, :type => "password" }
|
16
|
+
.buttons
|
17
|
+
%input{ :value => "Create account", :type => "submit" }
|
18
|
+
%a{:href => "/login", :class => 'sinatra_authentication_link'}
|
19
|
+
Login
|
20
|
+
- if Sinatra.const_defined?('FacebookObject')
|
21
|
+
.third_party_signup
|
22
|
+
%h3.section_title One click signup:
|
23
|
+
.login_link.facebook_login
|
24
|
+
= render_facebook_connect_link('Signup using facebook', :size => 'large')
|
25
|
+
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,133 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: redsafe
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.5
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ruby Shot
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
|
12
|
+
date: 2010-02-12 00:00:00 -07:00
|
13
|
+
default_executable:
|
14
|
+
dependencies:
|
15
|
+
- !ruby/object:Gem::Dependency
|
16
|
+
name: sinatra
|
17
|
+
type: :development
|
18
|
+
version_requirement:
|
19
|
+
version_requirements: !ruby/object:Gem::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">="
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: "0"
|
24
|
+
version:
|
25
|
+
- !ruby/object:Gem::Dependency
|
26
|
+
name: dm-core
|
27
|
+
type: :development
|
28
|
+
version_requirement:
|
29
|
+
version_requirements: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: "0"
|
34
|
+
version:
|
35
|
+
- !ruby/object:Gem::Dependency
|
36
|
+
name: dm-validations
|
37
|
+
type: :development
|
38
|
+
version_requirement:
|
39
|
+
version_requirements: !ruby/object:Gem::Requirement
|
40
|
+
requirements:
|
41
|
+
- - ">="
|
42
|
+
- !ruby/object:Gem::Version
|
43
|
+
version: "0"
|
44
|
+
version:
|
45
|
+
- !ruby/object:Gem::Dependency
|
46
|
+
name: dm-timestamps
|
47
|
+
type: :development
|
48
|
+
version_requirement:
|
49
|
+
version_requirements: !ruby/object:Gem::Requirement
|
50
|
+
requirements:
|
51
|
+
- - ">="
|
52
|
+
- !ruby/object:Gem::Version
|
53
|
+
version: "0"
|
54
|
+
version:
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: date
|
57
|
+
type: :development
|
58
|
+
version_requirement:
|
59
|
+
version_requirements: !ruby/object:Gem::Requirement
|
60
|
+
requirements:
|
61
|
+
- - ">="
|
62
|
+
- !ruby/object:Gem::Version
|
63
|
+
version: "0"
|
64
|
+
version:
|
65
|
+
- !ruby/object:Gem::Dependency
|
66
|
+
name: time
|
67
|
+
type: :development
|
68
|
+
version_requirement:
|
69
|
+
version_requirements: !ruby/object:Gem::Requirement
|
70
|
+
requirements:
|
71
|
+
- - ">="
|
72
|
+
- !ruby/object:Gem::Version
|
73
|
+
version: "0"
|
74
|
+
version:
|
75
|
+
description: Red Safe is a conveyor belt to get your web-based project on a fast roll.
|
76
|
+
email: domochoice(at)yahoo:com
|
77
|
+
executables: []
|
78
|
+
|
79
|
+
extensions: []
|
80
|
+
|
81
|
+
extra_rdoc_files:
|
82
|
+
- LICENSE
|
83
|
+
- README.rdoc
|
84
|
+
files:
|
85
|
+
- .document
|
86
|
+
- .gitignore
|
87
|
+
- GemcutterInstructions.rdoc
|
88
|
+
- LICENSE
|
89
|
+
- README.rdoc
|
90
|
+
- Rakefile
|
91
|
+
- lib/models/scarlet_letters.rb
|
92
|
+
- lib/models/sl_aah.rb
|
93
|
+
- lib/models/sl_user.rb
|
94
|
+
- lib/redsafe.rb
|
95
|
+
- lib/redsafe/version.rb
|
96
|
+
- lib/views/edit.haml
|
97
|
+
- lib/views/index.haml
|
98
|
+
- lib/views/login.haml
|
99
|
+
- lib/views/show.haml
|
100
|
+
- lib/views/signup.haml
|
101
|
+
- test/redsafe_test.rb
|
102
|
+
- test/test_helper.rb
|
103
|
+
has_rdoc: true
|
104
|
+
homepage: http://github.com/rubyshot/redsafe
|
105
|
+
licenses: []
|
106
|
+
|
107
|
+
post_install_message:
|
108
|
+
rdoc_options:
|
109
|
+
- --charset=UTF-8
|
110
|
+
require_paths:
|
111
|
+
- lib
|
112
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
113
|
+
requirements:
|
114
|
+
- - ">="
|
115
|
+
- !ruby/object:Gem::Version
|
116
|
+
version: "0"
|
117
|
+
version:
|
118
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
119
|
+
requirements:
|
120
|
+
- - ">="
|
121
|
+
- !ruby/object:Gem::Version
|
122
|
+
version: "0"
|
123
|
+
version:
|
124
|
+
requirements: []
|
125
|
+
|
126
|
+
rubyforge_project:
|
127
|
+
rubygems_version: 1.3.5
|
128
|
+
signing_key:
|
129
|
+
specification_version: 3
|
130
|
+
summary: This is a gem tool which simplifies signup functionality using various web services for connection credentials.
|
131
|
+
test_files:
|
132
|
+
- test/redsafe_test.rb
|
133
|
+
- test/test_helper.rb
|