| |   |
| 1 | 1 | (in no particular order) |
| 2 | 2 | |
| 3 | > If you do `git archive --format=tar --prefix=myproject/ HEAD | gzip > |
| 4 | > myproject.tar.gz`, when .gitattributes specifies files that have |
| 5 | > export-subst, it will expand keywords such as $Format:%cd$. Gitorious' |
| 6 | > "Download as gzipped tarball" apparently does not do this and I think |
| 7 | > it'd be pretty nice if it did. |
| 8 | |
| 3 | 9 | * Deal gracefully with markdown errors (and/or look into using the other markdown libary instead) |
| 4 | 10 | * Don't generate graphs with big "No Data", text even if there's no data |
| 5 | 11 | * Markdownify atom feed body for projects.atom |
| … | … | |
| 20 | 20 | * expire fragment caches for project+repos on deletion |
| 21 | 21 | *a Tone down the "owner" of a repository, or implement a proper "mirror" project type. |
| 22 | 22 | *b be able to mark a project as a "mirror" |
| 23 | | * reset password functionality |
| 24 | 23 | * Nicer diff stats |
| 25 | 24 | * more interesting project stats on frontpage |
| 26 | 25 | * parse git submodule data and link to project if submodule is in gitorious |
| toggle raw diff |
--- a/TODO.txt
+++ b/TODO.txt
@@ -1,5 +1,11 @@
(in no particular order)
+> If you do `git archive --format=tar --prefix=myproject/ HEAD | gzip >
+> myproject.tar.gz`, when .gitattributes specifies files that have
+> export-subst, it will expand keywords such as $Format:%cd$. Gitorious'
+> "Download as gzipped tarball" apparently does not do this and I think
+> it'd be pretty nice if it did.
+
* Deal gracefully with markdown errors (and/or look into using the other markdown libary instead)
* Don't generate graphs with big "No Data", text even if there's no data
* Markdownify atom feed body for projects.atom
@@ -14,7 +20,6 @@
* expire fragment caches for project+repos on deletion
*a Tone down the "owner" of a repository, or implement a proper "mirror" project type.
*b be able to mark a project as a "mirror"
-* reset password functionality
* Nicer diff stats
* more interesting project stats on frontpage
* parse git submodule data and link to project if submodule is in gitorious |
| |   |
| 36 | 36 | end |
| 37 | 37 | redirect_back_or_default('/') |
| 38 | 38 | end |
| 39 | |
| 40 | def forgot_password |
| 41 | end |
| 42 | |
| 43 | def reset_password |
| 44 | if params[:user] && user = User.find_by_email(params[:user][:email]) |
| 45 | # FIXME: should really be a two-step process: receive link, visiting it resets password |
| 46 | generated_password = user.reset_password! |
| 47 | Mailer.deliver_forgotten_password(user, generated_password) |
| 48 | flash[:notice] = "A new password has been sent to your email" |
| 49 | redirect_to(root_path) |
| 50 | else |
| 51 | flash[:error] = "Invalid email" |
| 52 | redirect_to forgot_password_users_path |
| 53 | end |
| 54 | end |
| 39 | 55 | end |
| toggle raw diff |
--- a/app/controllers/users_controller.rb
+++ b/app/controllers/users_controller.rb
@@ -36,4 +36,20 @@ class UsersController < ApplicationController
end
redirect_back_or_default('/')
end
+
+ def forgot_password
+ end
+
+ def reset_password
+ if params[:user] && user = User.find_by_email(params[:user][:email])
+ # FIXME: should really be a two-step process: receive link, visiting it resets password
+ generated_password = user.reset_password!
+ Mailer.deliver_forgotten_password(user, generated_password)
+ flash[:notice] = "A new password has been sent to your email"
+ redirect_to(root_path)
+ else
+ flash[:error] = "Invalid email"
+ redirect_to forgot_password_users_path
+ end
+ end
end |
| |   |
| 41 | 41 | Digest::SHA1.hexdigest("--#{salt}--#{password}--") |
| 42 | 42 | end |
| 43 | 43 | |
| 44 | def self.generate_random_password(password_size = 12) |
| 45 | characters = (("a".."z").to_a + ("0".."9").to_a) - %w[0 o i l 1] |
| 46 | (0...password_size).collect do |char| |
| 47 | characters[rand(characters.length)] |
| 48 | end.join |
| 49 | end |
| 50 | |
| 44 | 51 | # Activates the user in the database. |
| 45 | 52 | def activate |
| 46 | 53 | @activated = true |
| … | … | |
| 99 | 99 | save(false) |
| 100 | 100 | end |
| 101 | 101 | |
| 102 | def reset_password! |
| 103 | generated = User.generate_random_password |
| 104 | self.password = generated |
| 105 | self.password_confirmation = generated |
| 106 | self.save! |
| 107 | generated |
| 108 | end |
| 109 | |
| 102 | 110 | def can_write_to?(repository) |
| 103 | 111 | !!committerships.find_by_repository_id(repository.id) |
| 104 | 112 | end |
| toggle raw diff |
--- a/app/models/user.rb
+++ b/app/models/user.rb
@@ -41,6 +41,13 @@ class User < ActiveRecord::Base
Digest::SHA1.hexdigest("--#{salt}--#{password}--")
end
+ def self.generate_random_password(password_size = 12)
+ characters = (("a".."z").to_a + ("0".."9").to_a) - %w[0 o i l 1]
+ (0...password_size).collect do |char|
+ characters[rand(characters.length)]
+ end.join
+ end
+
# Activates the user in the database.
def activate
@activated = true
@@ -92,6 +99,14 @@ class User < ActiveRecord::Base
save(false)
end
+ def reset_password!
+ generated = User.generate_random_password
+ self.password = generated
+ self.password_confirmation = generated
+ self.save!
+ generated
+ end
+
def can_write_to?(repository)
!!committerships.find_by_repository_id(repository.id)
end |
| |   |
| 1 | Hello <%= @user.login -%>, |
| 2 | |
| 3 | Your new password is: <%= @password %> |
| 4 | |
| 5 | If you did not request a new password, then please do report this incident. |
| 6 | |
| 7 | Thank you |
| 8 | |
| 9 | http://<%= GitoriousConfig['gitorious_host'] %> |
| toggle raw diff |
--- /dev/null
+++ b/app/views/mailer/forgotten_password.rhtml
@@ -0,0 +1,9 @@
+Hello <%= @user.login -%>,
+
+Your new password is: <%= @password %>
+
+If you did not request a new password, then please do report this incident.
+
+Thank you
+
+http://<%= GitoriousConfig['gitorious_host'] %>
\ No newline at end of file |
| |   |
| 20 | 20 | <p><%= submit_tag 'Log in' %></p> |
| 21 | 21 | <% end -%> |
| 22 | 22 | |
| 23 | | <% content_for(:submenu) do -%> |
| 24 | | <ul> |
| 25 | | <li><%= link_to "Register", new_user_path -%></li> |
| 26 | | </ul> |
| 27 | | <% end -%> |
| 23 | <p> |
| 24 | <small> |
| 25 | <%= link_to "Register", new_user_path -%> |
| 26 | | <%= link_to "Forgotten your password?", forgot_password_users_path -%> |
| 27 | </small> |
| 28 | </p> |
| toggle raw diff |
--- a/app/views/sessions/new.html.erb
+++ b/app/views/sessions/new.html.erb
@@ -20,8 +20,9 @@
<p><%= submit_tag 'Log in' %></p>
<% end -%>
-<% content_for(:submenu) do -%>
- <ul>
- <li><%= link_to "Register", new_user_path -%></li>
- </ul>
-<% end -%>
\ No newline at end of file
+<p>
+ <small>
+ <%= link_to "Register", new_user_path -%>
+ | <%= link_to "Forgotten your password?", forgot_password_users_path -%>
+ </small>
+</p> |
| |   |
| 1 | <h1>Forgot your password?</h1> |
| 2 | |
| 3 | |
| 4 | <% form_for :user, :url => reset_password_users_path do |f| -%> |
| 5 | <p> |
| 6 | <%= f.label :email -%><br/> |
| 7 | <%= f.text_field :email, :class => "text" -%> |
| 8 | </p> |
| 9 | |
| 10 | <p><%= f.submit 'Send me a new password' %></p> |
| 11 | <% end -%> |
| toggle raw diff |
--- /dev/null
+++ b/app/views/users/forgot_password.html.erb
@@ -0,0 +1,11 @@
+<h1>Forgot your password?</h1>
+
+
+<% form_for :user, :url => reset_password_users_path do |f| -%>
+ <p>
+ <%= f.label :email -%><br/>
+ <%= f.text_field :email, :class => "text" -%>
+ </p>
+
+ <p><%= f.submit 'Send me a new password' %></p>
+<% end -%> |
| |   |
| 24 | 24 | account.resources :keys |
| 25 | 25 | end |
| 26 | 26 | map.connect "users/activate/:activation_code", :controller => "users", :action => "activate" |
| 27 | | map.resources :users, :requirements => {:id => /.+/} |
| 27 | map.resources :users, :requirements => {:id => /.+/}, :collection => { |
| 28 | :forgot_password => :get, |
| 29 | :reset_password => :post, |
| 30 | } |
| 28 | 31 | map.resource :sessions |
| 29 | 32 | map.with_options(:controller => "projects", :action => "category") do |project_cat| |
| 30 | 33 | project_cat.projects_category "projects/category/:id" |
| toggle raw diff |
--- a/config/routes.rb
+++ b/config/routes.rb
@@ -24,7 +24,10 @@ ActionController::Routing::Routes.draw do |map|
account.resources :keys
end
map.connect "users/activate/:activation_code", :controller => "users", :action => "activate"
- map.resources :users, :requirements => {:id => /.+/}
+ map.resources :users, :requirements => {:id => /.+/}, :collection => {
+ :forgot_password => :get,
+ :reset_password => :post,
+ }
map.resource :sessions
map.with_options(:controller => "projects", :action => "category") do |project_cat|
project_cat.projects_category "projects/category/:id" |
| |   |
| 97 | 97 | assigns[:commits_last_week].kind_of?(Fixnum).should == true |
| 98 | 98 | (assigns[:commits_last_week] >= 0).should == true |
| 99 | 99 | end |
| 100 | |
| 101 | describe "#forgot_password" do |
| 102 | it "GETs the page fine for everyone" do |
| 103 | get :forgot_password |
| 104 | response.should be_success |
| 105 | response.should render_template("forgot_password") |
| 106 | end |
| 107 | end |
| 108 | |
| 109 | describe "#reset_password" do |
| 110 | it "redirects to forgot_password if nothing was found" do |
| 111 | post :reset_password, :user => {:email => "xxx"} |
| 112 | response.should redirect_to(forgot_password_users_path) |
| 113 | flash[:error].should match(/invalid email/i) |
| 114 | end |
| 115 | |
| 116 | it "sends a new password if email was found" do |
| 117 | u = users(:johan) |
| 118 | User.should_receive(:generate_random_password).and_return("secret") |
| 119 | Mailer.should_receive(:deliver_forgotten_password).with(u, "secret") |
| 120 | post :reset_password, :user => {:email => u.email} |
| 121 | response.should redirect_to(root_path) |
| 122 | flash[:notice].should == "A new password has been sent to your email" |
| 123 | |
| 124 | User.authenticate(u.email, "secret").should_not be_nil |
| 125 | end |
| 126 | end |
| 100 | 127 | end |
| toggle raw diff |
--- a/spec/controllers/users_controller_spec.rb
+++ b/spec/controllers/users_controller_spec.rb
@@ -97,4 +97,31 @@ describe UsersController do
assigns[:commits_last_week].kind_of?(Fixnum).should == true
(assigns[:commits_last_week] >= 0).should == true
end
+
+ describe "#forgot_password" do
+ it "GETs the page fine for everyone" do
+ get :forgot_password
+ response.should be_success
+ response.should render_template("forgot_password")
+ end
+ end
+
+ describe "#reset_password" do
+ it "redirects to forgot_password if nothing was found" do
+ post :reset_password, :user => {:email => "xxx"}
+ response.should redirect_to(forgot_password_users_path)
+ flash[:error].should match(/invalid email/i)
+ end
+
+ it "sends a new password if email was found" do
+ u = users(:johan)
+ User.should_receive(:generate_random_password).and_return("secret")
+ Mailer.should_receive(:deliver_forgotten_password).with(u, "secret")
+ post :reset_password, :user => {:email => u.email}
+ response.should redirect_to(root_path)
+ flash[:notice].should == "A new password has been sent to your email"
+
+ User.authenticate(u.email, "secret").should_not be_nil
+ end
+ end
end |
| |   |
| 57 | 57 | Mailer.deliver(mail) |
| 58 | 58 | Mailer.deliveries.should == [mail] |
| 59 | 59 | end |
| 60 | |
| 61 | it "sends forgotten_password" do |
| 62 | user = users(:johan) |
| 63 | mail = Mailer.create_forgotten_password(user, "newpassword") |
| 64 | |
| 65 | mail.to.should == [user.email] |
| 66 | mail.subject.should == "[Gitorious] Your new password" |
| 67 | mail.body.should match(/your new password is: newpassword/i) |
| 68 | |
| 69 | Mailer.deliver(mail) |
| 70 | Mailer.deliveries.should == [mail] |
| 71 | end |
| 60 | 72 | |
| 61 | 73 | end |
| toggle raw diff |
--- a/spec/models/mailer_spec.rb
+++ b/spec/models/mailer_spec.rb
@@ -57,5 +57,17 @@ describe Mailer do
Mailer.deliver(mail)
Mailer.deliveries.should == [mail]
end
+
+ it "sends forgotten_password" do
+ user = users(:johan)
+ mail = Mailer.create_forgotten_password(user, "newpassword")
+
+ mail.to.should == [user.email]
+ mail.subject.should == "[Gitorious] Your new password"
+ mail.body.should match(/your new password is: newpassword/i)
+
+ Mailer.deliver(mail)
+ Mailer.deliveries.should == [mail]
+ end
end |
| |   |
| 141 | 141 | }.should raise_error(ActiveRecord::RecordNotFound) |
| 142 | 142 | end |
| 143 | 143 | |
| 144 | it "generates some randomly password" do |
| 145 | User.generate_random_password.should match(/\w+/) |
| 146 | User.generate_random_password.length.should == 12 |
| 147 | User.generate_random_password(16).length.should == 16 |
| 148 | User.generate_random_password(5).length.should == 5 |
| 149 | end |
| 150 | |
| 151 | it "resets a password to something" do |
| 152 | u = users(:johan) |
| 153 | password = u.reset_password! |
| 154 | User.authenticate(u.email, password).should_not be_nil |
| 155 | end |
| 156 | |
| 144 | 157 | protected |
| 145 | 158 | def create_user(options = {}) |
| 146 | 159 | u = User.new({ |
| toggle raw diff |
--- a/spec/models/user_spec.rb
+++ b/spec/models/user_spec.rb
@@ -141,6 +141,19 @@ describe User do
}.should raise_error(ActiveRecord::RecordNotFound)
end
+ it "generates some randomly password" do
+ User.generate_random_password.should match(/\w+/)
+ User.generate_random_password.length.should == 12
+ User.generate_random_password(16).length.should == 16
+ User.generate_random_password(5).length.should == 5
+ end
+
+ it "resets a password to something" do
+ u = users(:johan)
+ password = u.reset_password!
+ User.authenticate(u.email, password).should_not be_nil
+ end
+
protected
def create_user(options = {})
u = User.new({ |