Skip to content

Commit 49d66a8

Browse files
authored
Add setting to control user signups (stringer-rss#1068)
**What** This allows admins to enable and disable user signups in the app. **Why** This will help prevent bots from creating accounts if they manage to find a stringer instance online, as well as allowing admins to control who can create accounts. Fixes [stringer-rss#1063][is]. [is]: stringer-rss#1063
1 parent 3360e77 commit 49d66a8

25 files changed

Lines changed: 367 additions & 11 deletions

Gemfile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,4 +50,5 @@ end
5050
group :test do
5151
gem "selenium-webdriver"
5252
gem "webdrivers"
53+
gem "with_model"
5354
end

Gemfile.lock

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,8 @@ GEM
333333
websocket-extensions (>= 0.1.0)
334334
websocket-extensions (0.1.5)
335335
will_paginate (4.0.0)
336+
with_model (2.1.6)
337+
activerecord (>= 5.2)
336338
xpath (3.2.0)
337339
nokogiri (~> 1.8)
338340
zeitwerk (2.6.8)
@@ -376,9 +378,10 @@ DEPENDENCIES
376378
webdrivers
377379
webmock
378380
will_paginate
381+
with_model
379382

380383
RUBY VERSION
381384
ruby 3.2.2
382385

383386
BUNDLED WITH
384-
2.3.25
387+
2.4.13

app/assets/stylesheets/application.css

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -486,8 +486,12 @@ li.feed .remove-feed a:hover {
486486
padding-top: 10px;
487487
}
488488

489+
.setup__label {
490+
font-weight: bold;
491+
}
492+
489493
.setup {
490-
width: 350px;
494+
width: 500px;
491495
margin: 0 auto;
492496
padding-top: 100px;
493497
}

app/commands/cast_boolean.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# frozen_string_literal: true
2+
3+
module CastBoolean
4+
TRUE_VALUES = Set.new(["true", true, "1"]).freeze
5+
FALSE_VALUES = Set.new(["false", false, "0"]).freeze
6+
7+
def self.call(boolean)
8+
unless (TRUE_VALUES + FALSE_VALUES).include?(boolean)
9+
raise(ArgumentError, "cannot cast to boolean: #{boolean.inspect}")
10+
end
11+
12+
TRUE_VALUES.include?(boolean)
13+
end
14+
end

app/controllers/passwords_controller.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
class PasswordsController < ApplicationController
44
skip_before_action :complete_setup, only: [:new, :create]
55
skip_before_action :authenticate_user, only: [:new, :create]
6+
before_action :check_signups_enabled, only: [:new, :create]
67

78
def new
89
authorization.skip
@@ -35,6 +36,10 @@ def update
3536

3637
private
3738

39+
def check_signups_enabled
40+
redirect_to(login_path) unless Setting::UserSignup.enabled?
41+
end
42+
3843
def password_params
3944
params.require(:user)
4045
.permit(:password_challenge, :password, :password_confirmation)
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
# frozen_string_literal: true
2+
3+
class SettingsController < ApplicationController
4+
def index
5+
authorization.skip
6+
end
7+
8+
def update
9+
authorization.skip
10+
11+
setting = Setting.find(params[:id])
12+
setting.update!(setting_params)
13+
14+
redirect_to(settings_path)
15+
end
16+
17+
private
18+
19+
def setting_params
20+
params.require(:setting).permit(:enabled)
21+
end
22+
end

app/models/application_record.rb

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,20 @@
33
class ApplicationRecord < ActiveRecord::Base
44
primary_abstract_class
55

6+
def self.boolean_accessor(attribute, key, default: false)
7+
store_accessor(attribute, key)
8+
9+
define_method(key) do
10+
value = super()
11+
value.nil? ? default : CastBoolean.call(value)
12+
end
13+
alias_method(:"#{key}?", :"#{key}")
14+
15+
define_method(:"#{key}=") do |value|
16+
super(value.nil? ? default : CastBoolean.call(value))
17+
end
18+
end
19+
620
def error_messages
721
errors.full_messages.join(", ")
822
end

app/models/setting.rb

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
# frozen_string_literal: true
2+
3+
class Setting < ApplicationRecord
4+
validates :type, presence: true, uniqueness: true
5+
end

app/models/setting/user_signup.rb

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
# frozen_string_literal: true
2+
3+
class Setting::UserSignup < Setting
4+
boolean_accessor :data, :enabled, default: false
5+
6+
validates :enabled, inclusion: { in: [true, false] }
7+
8+
def self.first
9+
first_or_create!
10+
end
11+
12+
def self.enabled?
13+
first_or_create!.enabled? || User.none?
14+
end
15+
end

app/views/layouts/_footer.html.erb

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<div class="container">
22
<div class="row-fluid">
3-
<div class="span6">
3+
<div class="span8">
44
<ul class="footer-links">
55
<% if current_user %>
66
<li><a href="/logout"><%= t('layout.logout') %></a></li>
@@ -13,12 +13,16 @@
1313
<li class="muted">·</li>
1414
<li><%= link_to(t('layout.profile'), edit_profile_path) %></li>
1515
<li class="muted">·</li>
16+
<% if current_user.admin? %>
17+
<li><%= link_to(t('layout.admin_settings'), settings_path) %></li>
18+
<li class="muted">·</li>
19+
<% end %>
1620
<% end %>
1721

1822
<li><a href="https://github.com/stringer-rss/stringer"><%= t('layout.support') %></a></li>
1923
</ul>
2024
</div>
21-
<div class="span6">
25+
<div class="span4">
2226
<p class="pull-right">
2327
<b><%= t('layout.hey') %></b> <%= t('layout.back_to_work') %>
2428
</p>

0 commit comments

Comments
 (0)