mirror of
https://github.com/neocities/neocities.git
synced 2025-04-24 17:22:35 +02:00
Finish creation and signin flow
This commit is contained in:
parent
4ddd244588
commit
0aaf894fa3
13 changed files with 182 additions and 43 deletions
36
app.rb
36
app.rb
|
@ -1,10 +1,17 @@
|
|||
require './environment.rb'
|
||||
|
||||
use Rack::Session::Cookie, key: 'neocities',
|
||||
path: '/',
|
||||
expire_after: 31556926, # one year in seconds
|
||||
secret: $config['session_secret']
|
||||
|
||||
get '/' do
|
||||
dashboard_if_signed_in
|
||||
slim :index
|
||||
end
|
||||
|
||||
get '/new' do
|
||||
dashboard_if_signed_in
|
||||
@site = Site.new
|
||||
slim :'new'
|
||||
end
|
||||
|
@ -14,23 +21,17 @@ get '/dashboard' do
|
|||
end
|
||||
|
||||
get '/signin' do
|
||||
dashboard_if_signed_in
|
||||
slim :'signin'
|
||||
end
|
||||
|
||||
post '/create' do
|
||||
@site = Site.new username: params[:username], password: params[:password], email: params[:email]
|
||||
dashboard_if_signed_in
|
||||
@site = Site.new username: params[:username], password: params[:password], email: params[:email], new_tags: params[:tags]
|
||||
if @site.valid?
|
||||
DB.transaction { @site.save }
|
||||
|
||||
@server = Server.with_slots_available
|
||||
|
||||
if @server.nil?
|
||||
raise 'no slots available'
|
||||
end
|
||||
|
||||
@site.server = @server
|
||||
@site.save
|
||||
|
||||
session[:username] = @site.username
|
||||
session[:id] = @site.id
|
||||
redirect '/dashboard'
|
||||
else
|
||||
slim :'/new'
|
||||
|
@ -38,8 +39,10 @@ post '/create' do
|
|||
end
|
||||
|
||||
post '/signin' do
|
||||
dashboard_if_signed_in
|
||||
if Site.valid_login? params[:username], params[:password]
|
||||
session[:username] = params[:username]
|
||||
site = Site[username: params[:username]]
|
||||
session[:id] = site.id
|
||||
redirect '/dashboard'
|
||||
else
|
||||
flash[:error] = 'Invalid login.'
|
||||
|
@ -49,8 +52,7 @@ end
|
|||
|
||||
get '/signout' do
|
||||
require_login
|
||||
session[:username] = nil
|
||||
session[:timezone] = nil
|
||||
session[:id] = nil
|
||||
redirect '/'
|
||||
end
|
||||
|
||||
|
@ -63,5 +65,9 @@ def require_login
|
|||
end
|
||||
|
||||
def signed_in?
|
||||
!session[:username].nil?
|
||||
!session[:id].nil?
|
||||
end
|
||||
|
||||
def current_site
|
||||
@site ||= Site[id: session[:id]]
|
||||
end
|
|
@ -1,2 +1,3 @@
|
|||
development:
|
||||
database: 'postgres://localhost/neocities'
|
||||
database: 'postgres://localhost/neocities'
|
||||
session_secret: SETSOMETHINGHERE
|
|
@ -1,7 +1,8 @@
|
|||
Sequel.migration do
|
||||
up {
|
||||
DB.create_table! :sites do
|
||||
String :username, primary_key: true
|
||||
primary_key :id
|
||||
String :username
|
||||
String :email
|
||||
String :password
|
||||
Integer :server_id
|
||||
|
|
|
@ -3,7 +3,6 @@ Sequel.migration do
|
|||
DB.create_table! :tags do
|
||||
primary_key :id
|
||||
String :name
|
||||
DateTime :created_at
|
||||
end
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +0,0 @@
|
|||
Sequel.migration do
|
||||
up {
|
||||
DB.create_table! :site_tags do
|
||||
Integer :site_id
|
||||
Integer :tag_id
|
||||
end
|
||||
}
|
||||
|
||||
down {
|
||||
DB.drop_table :site_tags
|
||||
}
|
||||
end
|
12
migrations/004_create_sites_tags.rb
Normal file
12
migrations/004_create_sites_tags.rb
Normal file
|
@ -0,0 +1,12 @@
|
|||
Sequel.migration do
|
||||
up {
|
||||
DB.create_table! :sites_tags do
|
||||
foreign_key :site_id, :sites
|
||||
foreign_key :tag_id, :tags
|
||||
end
|
||||
}
|
||||
|
||||
down {
|
||||
DB.drop_table :sites_tags
|
||||
}
|
||||
end
|
|
@ -1,8 +1,7 @@
|
|||
class Site < Sequel::Model
|
||||
MINIMUM_PASSWORD_LENGTH = 5
|
||||
|
||||
unrestrict_primary_key
|
||||
many_to_one :server
|
||||
many_to_many :tags
|
||||
|
||||
class << self
|
||||
def valid_login?(username, plaintext)
|
||||
|
@ -30,10 +29,37 @@ class Site < Sequel::Model
|
|||
values[:password] = BCrypt::Password.create plaintext, cost: (self.class.bcrypt_cost || BCrypt::Engine::DEFAULT_COST)
|
||||
end
|
||||
|
||||
def after_save
|
||||
if @new_tag_strings
|
||||
@new_tag_strings.each do |new_tag_string|
|
||||
add_tag Tag[name: new_tag_string] || Tag.create(name: new_tag_string)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def after_create
|
||||
DB['update servers set slots_available=slots_available-1 where id=?', self.server.id].first
|
||||
end
|
||||
|
||||
def new_tags=(tags_string)
|
||||
tags_string.gsub! /[^a-zA-Z0-9, ]/, ''
|
||||
tags = tags_string.split ','
|
||||
tags.collect! {|c| (c.match(/^\w+\s\w+/) || c.match(/^\w+/)).to_s }
|
||||
@new_tag_strings = tags
|
||||
end
|
||||
|
||||
def before_validation
|
||||
self.server ||= Server.with_slots_available
|
||||
end
|
||||
|
||||
def validate
|
||||
super
|
||||
|
||||
if values[:username].nil? || values[:username].empty?
|
||||
if server.nil?
|
||||
errors.add :over_capacity, 'We are currently at capacity, and cannot create your home page. We will fix this shortly. Please come back later and try again, our apologies.'
|
||||
end
|
||||
|
||||
if values[:username].nil? || values[:username].empty? || values[:username].match(/[^\w.-]/i)
|
||||
errors.add :username, 'A valid username is required.'
|
||||
end
|
||||
|
||||
|
|
3
models/tag.rb
Normal file
3
models/tag.rb
Normal file
|
@ -0,0 +1,3 @@
|
|||
class Tag < Sequel::Model
|
||||
many_to_many :sites
|
||||
end
|
|
@ -0,0 +1,95 @@
|
|||
require_relative './environment'
|
||||
|
||||
include Rack::Test::Methods
|
||||
|
||||
def app; App end
|
||||
def status; last_response.status end
|
||||
def headers; last_response.headers end
|
||||
def body; last_response.body end
|
||||
|
||||
SimpleCov.command_name 'minitest'
|
||||
|
||||
describe 'index' do
|
||||
it 'loads' do
|
||||
get '/'
|
||||
status.must_equal 200
|
||||
end
|
||||
end
|
||||
|
||||
describe 'signin' do
|
||||
it 'fails for missing login' do
|
||||
post '/signin', username: 'derpie', password: 'lol'
|
||||
fail_signin
|
||||
end
|
||||
|
||||
it 'fails for bad password' do
|
||||
@site = Fabricate :site
|
||||
post '/signin', username: @site.username, password: 'derp'
|
||||
fail_signin
|
||||
end
|
||||
|
||||
it 'fails for no input' do
|
||||
post '/signin'
|
||||
fail_signin
|
||||
end
|
||||
|
||||
it 'succeeds for valid input' do
|
||||
password = '1tw0rkz'
|
||||
@account = Fabricate :account, password: password
|
||||
post '/accounts/signin', username: @account.email, password: password
|
||||
headers['Location'].must_equal 'http://example.org/dashboard'
|
||||
mock_dashboard_calls @account.email
|
||||
get '/dashboard'
|
||||
body.must_match /Dashboard/
|
||||
end
|
||||
end
|
||||
|
||||
describe 'account creation' do
|
||||
it 'fails for no input' do
|
||||
post '/accounts/create'
|
||||
status.must_equal 200
|
||||
body.must_match /There were some errors.+Valid email address is required.+Password must be/
|
||||
end
|
||||
|
||||
it 'fails with invalid email' do
|
||||
post '/accounts/create', email: 'derplol'
|
||||
status.must_equal 200
|
||||
body.must_match /errors.+valid email/i
|
||||
end
|
||||
|
||||
it 'fails with invalid password' do
|
||||
post '/accounts/create', 'email@example.com', password: 'sdd'
|
||||
status.must_equal 200
|
||||
body.must_match /errors.+Password must be at least #{Account::MINIMUM_PASSWORD_LENGTH} characters/i
|
||||
end
|
||||
|
||||
it 'succeeds with valid info' do
|
||||
account_attributes = Fabricate.attributes_for :account
|
||||
|
||||
mock_dashboard_calls account_attributes[:email]
|
||||
|
||||
post '/accounts/create', account_attributes
|
||||
status.must_equal 302
|
||||
headers['Location'].must_equal 'http://example.org/dashboard'
|
||||
|
||||
get '/dashboard'
|
||||
body.must_match /Dashboard/
|
||||
end
|
||||
end
|
||||
|
||||
describe 'temporary account login' do
|
||||
end
|
||||
|
||||
def fail_signin
|
||||
headers['Location'].must_equal 'http://example.org/'
|
||||
get '/'
|
||||
body.must_match /invalid signin/i
|
||||
end
|
||||
|
||||
def api_url
|
||||
uri = Addressable::URI.parse $config['bitcoind_rpchost'] ? $config['bitcoind_rpchost'] : 'http://localhost'
|
||||
uri.port = 8332 if uri.port.nil?
|
||||
uri.user = $config['bitcoind_rpcuser'] if uri.user.nil?
|
||||
uri.password = $config['bitcoind_rpcpassword'] if uri.password.nil?
|
||||
"#{uri.to_s}/"
|
||||
end
|
4
tests/fabricators/site_fabricator.rb
Normal file
4
tests/fabricators/site_fabricator.rb
Normal file
|
@ -0,0 +1,4 @@
|
|||
Fabricator(:site) do
|
||||
username { Faker::Internet.email }
|
||||
password { 'abcde' }
|
||||
end
|
|
@ -1,4 +1,4 @@
|
|||
.row
|
||||
.span12
|
||||
|
||||
h1 Dashboard!
|
||||
h1 Dashboard
|
|
@ -19,7 +19,7 @@ html
|
|||
a.brand href="/" NeoCities
|
||||
ul.nav.pull-right
|
||||
- if signed_in?
|
||||
li.navbar-text: strong style="color: #7AB800" #{session[:username]}
|
||||
li.navbar-text: strong style="color: #7AB800" #{current_site.username}
|
||||
li: a href="/signout" style="color: #B94A48" Signout
|
||||
- else
|
||||
li: a href="/signin" <b>Sign in</b>
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
.row
|
||||
.span8.offset2
|
||||
.alert.alert-block.alert-error
|
||||
p Please correct the following errors:
|
||||
p There were errors creating your home page:
|
||||
- @site.errors.each do |error|
|
||||
p = error.last.first
|
||||
|
||||
|
@ -14,17 +14,17 @@
|
|||
|
||||
.row
|
||||
.span6
|
||||
p First, enter a username. This will be used to login to your site.<br>It will also be the path of your web site.
|
||||
p First, enter a username. This will also be used as your site path.<br><b>Do not forget this, it will be used to sign in to and manage your home page.</b><br>It cannot contain spaces, and can only use the following characters: a-z A-Z 0-9 . _ -
|
||||
|
||||
.row
|
||||
.span1
|
||||
h5 Username
|
||||
.span6
|
||||
p http://neocities.org/<input name="username" type="text" placeholder="yourusername">
|
||||
p http://neocities.org/<input name="username" type="text" placeholder="yourusername" value="#{@site.username}">
|
||||
|
||||
.row
|
||||
.span6
|
||||
p Next, enter a password. This will be used to allow you to login. Minimum 5 characters.
|
||||
p Next, enter a password. This will be used to allow you to login. Minimum 5 characters. If you don't make it a good password, Dade Murphy from the movie Hackers will come in and steal your "garbage files".
|
||||
|
||||
.row
|
||||
.span1
|
||||
|
@ -34,26 +34,30 @@
|
|||
|
||||
.row
|
||||
.span6
|
||||
p Now you can enter an e-mail address. You don't have to provide one, but <b>we will not be able to reset your password without it, so don't lose your username and password if you leave this blank!</b>
|
||||
p Now you can enter an e-mail address. Your e-mail address is private and we will not show it to anyone for any reason. You don't have to provide one, but <b>we will not be able to reset your password without it, so don't lose your username and password if you leave this blank!</b>
|
||||
.row
|
||||
.span1
|
||||
h5 Email
|
||||
.span6
|
||||
input name="email" type="text" placeholder="youremail@example.com"
|
||||
input name="email" type="text" placeholder="youremail@example.com" value="#{@site.email}"
|
||||
|
||||
|
||||
.row
|
||||
.span6
|
||||
p
|
||||
| Enter some tags! Tags will allow others to find your site based on your interests, or your site's theme. <b>Separate multiple tags with commas</b>. Don't think too hard about this, you can change them later. You can have a maximum of ten tags, and there is a two word per tag maximum.
|
||||
| You can optionally enter some tags! Tags will allow others to find your site based on your interests, or your site's theme. <b>Separate multiple tags with commas</b>. Don't think too hard about this, you can change them later. You can have a maximum of ten tags, and there is a two word per tag maximum (extra words in a tag will be removed).
|
||||
|
||||
.row
|
||||
.span1
|
||||
h5 Tags
|
||||
.span6
|
||||
p: input name="tags" type="text" style="width: 400px" placeholder="pokemon, video games, bulbasaur"
|
||||
p: input name="tags" type="text" style="width: 400px" placeholder="pokemon, video games, bulbasaur" value="#{params[:tags]}"
|
||||
|
||||
|
||||
.row
|
||||
.span6
|
||||
h3 You're done. Just click the button below!
|
||||
|
||||
.row style="margin-top: 30px"
|
||||
.span3.offset1
|
||||
input.btn.btn-success.btn-large type="submit" value="Create Home Page"
|
Loading…
Add table
Reference in a new issue