Skip to content

Commit

Permalink
Add username field and various hub improvements
Browse files Browse the repository at this point in the history
Because we already have users without a username, it is not a
required field, but it is present in the sign up form.

Also:
- Rearrange user form so email is the first field instead of name
- Use it in hub to provide a list of sites owned by a user
- Add some hub test coverage
- Refactor the javascript for allowing on valid char
- Refactor the hub controller
- Remove hub_tags. Let's not carry the dead code around any more.
- Bump version to 0.0.4

(Probably should have split this into mutiple commits, but never
mind.)
  • Loading branch information
simonbaird committed Feb 23, 2021
1 parent 143f8e8 commit 6f1c541
Show file tree
Hide file tree
Showing 23 changed files with 276 additions and 115 deletions.
12 changes: 12 additions & 0 deletions rails/app/assets/stylesheets/hub.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,12 @@ h1 {
color: #bbb;
font-size: 65%;
}

.gravatar {
border-radius: 5px;
margin-right: 0.2em;
margin-top: -6px;
}
}

.nav-link {
Expand Down Expand Up @@ -39,13 +45,19 @@ h1 {
font-size: 90%;
}

svg.bi {
color: #aaa;
}

.gravatar {
margin-top: -2px;
border-radius: 2px;
}
}

.site-tags {
margin-left: 0.4em;
margin-top: 2px;
font-size: 90%;
}
}
Expand Down
4 changes: 2 additions & 2 deletions rails/app/controllers/application_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -18,8 +18,8 @@ def redirect_www_requests
end

def permit_devise_params
devise_parameter_sanitizer.permit(:sign_up, keys: [:name])
devise_parameter_sanitizer.permit(:account_update, keys: [:name, :use_gravatar])
devise_parameter_sanitizer.permit(:sign_up, keys: [:name, :username])
devise_parameter_sanitizer.permit(:account_update, keys: [:name, :username, :use_gravatar])
end

def require_admin_user!
Expand Down
83 changes: 37 additions & 46 deletions rails/app/controllers/hub_controller.rb
Original file line number Diff line number Diff line change
@@ -1,62 +1,28 @@
class HubController < ApplicationController
before_action :prepare_sorting,
:prepare_searching,
:prepare_tags,
:prepare_sites_and_render

def index
render_hub
end

def tag
@tag = params[:tag]
render_hub
end

# (Unused currently)
def twplugins
end

# (Unused currently)
def twdocs
end

private

def prepare_sites_and_render
@sites = Site.searchable.order(@sort_by[:field])
@sites = @sites.tagged_with(@tag) if @tag.present?
@sites = @sites.search_for(@search) if @search.present?
@sites = @sites.paginate(page: params[:page])

render action: :index
end

def prepare_tags
@hub_tags = Settings.hub_tags
@tag_tabs = Site.tags_for_searchable_sites.limit(4).pluck(:name)

# (Unused currently since there are no hub_tags)
if @hub_tags.keys.include?(action_name)
tag_info = @hub_tags[action_name]
@tag = tag_info[:tag]
@title = tag_info[:title]
@tag_description = tag_info[:description]

elsif params[:tag]
@tag = params[:tag]
# Beware that @tag is html unsafe
@tag_tabs = @tag_tabs.prepend(@tag).uniq
@tag_description = "Searchable sites tagged with '#{@tag}'."

def user
if params[:username].present? && user = User.find_by_username(params[:username])
@user = user
render_hub
else
@title = "Tiddlyhost Hub"
@tag_description = "If you mark your site as 'Searchable' it will be listed here."
# TODO: 404 page here maybe
redirect_to '/hub'
end
end

def prepare_searching
@search = params[:search]
end
private

def prepare_sorting
def render_hub
# Prepare sort options
@sort_options = {
'views' => {
name: 'view count',
Expand All @@ -69,6 +35,31 @@ def prepare_sorting
}

@sort_by = @sort_options[params[:sort]] || @sort_options['views']

# Prepare search
@search = params[:search]

# Prepare tag tabs
@tag_tabs = Site.tags_for_searchable_sites.limit(4).pluck(:name)
@tag_tabs = @tag_tabs.prepend(@tag).uniq if @tag.present?

# Apply sorting
@sites = Site.searchable.order(@sort_by[:field])

# Apply tag filtering
@sites = @sites.tagged_with(@tag) if @tag.present?

# Apply user filtering
@sites = @sites.where(user_id: @user.id) if @user.present?

# Apply search filtering
@sites = @sites.search_for(@search) if @search.present?

# Paginate
@sites = @sites.paginate(page: params[:page])

# Render
render action: :index
end

end
2 changes: 1 addition & 1 deletion rails/app/helpers/application_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def bi_icon(icon, opts={})
class: ["bi"].append(opts.delete(:class)).compact,
height: "1.2em",
width: "1.4em",
style: "margin-top:-3px;margin-right:4px;#{opts.delete(:style)}")
style: "margin-top:-3px;margin-right:3px;#{opts.delete(:style)}")

content_tag(:svg, opts) do
content_tag(:use, nil, "xlink:href" =>
Expand Down
6 changes: 1 addition & 5 deletions rails/app/helpers/sites_helper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,7 @@ def site_tags(site)
end

def tag_url(tag_name)
if hub_action = Settings.hub_tags_lookup[tag_name]
"/hub/#{hub_action}"
else
"/hub/tag/#{tag_name}"
end
"/hub/tag/#{tag_name}"
end

def clickable_site_tags(site)
Expand Down
42 changes: 28 additions & 14 deletions rails/app/javascript/packs/application.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,21 +20,35 @@ $(document).ready(function(){
event.preventDefault();
})

// Make it so the user can't easily type invalid names.
// We'll validate the name on the server as well, see app/models/site.
$('#site_name').on('keyup', function(){
$(this).val(
$(this).val().
// Remove anything that's not a letter, numeral or dash
replace(/[^0-9a-z-]/, '').
// Replace consecutive dashes with a single dash
replace(/[-]{2,}/, '-').
// Remove leading dashes
// (Don't remove trailing dashes since it makes it hard to type
// names with dashes. The server will invalidate them anyway.)
replace(/^-/, '')
var limitChars = function() {
var inputField = $(this);

if (inputField.attr('id') == 'site_name') {
// Allow lowercase letters, numerals and dashes
var notAllowed = /[^0-9a-z-]/;
}
else { // id == 'user_username"
// Same thing but also allow uppercase
var notAllowed = /[^0-9a-zA-Z-]/;
}

var currentVal = inputField.val();
inputField.val(currentVal.
// Remove any disallowed chars
replace(notAllowed, '').
// Replace consecutive dashes with a single dash
replace(/[-]{2,}/, '-').
// Remove leading dashes
// (Don't remove trailing dashes since it makes it hard to type
// names with dashes. The server will invalidate them anyway.)
replace(/^-/, '')
);
});
};

// Make it so the user can't easily type invalid site names or usernames.
// We'll validate server-side as well, see User and Site model validations.
$('input#site_name').on('keyup', limitChars);
$('input#user_username').on('keyup', limitChars);

// If site is set to private, automatically make it unsearchable
// If site is set to searchable, automatically make it public
Expand Down
22 changes: 22 additions & 0 deletions rails/app/models/user.rb
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,28 @@ class User < ApplicationRecord
belongs_to :plan
validates_presence_of :name

validates :username,
uniqueness: {
case_sensitive: false,
},
length: {
minimum: 3,
maximum: 30,
allow_blank: true,
},
format: {
# Must be upper- or lowercase letters, numerals, and dashes
# Must not have more than one consecutive dash
# Must not start or end with a dash
# (See also app/javascript/packs/application.js)
without: / [^A-Za-z0-9-] | -- | ^- | -$ /x,
message: "'%{value}' is not allowed. Please choose a different username.",
}

def username_or_name
username.presence || name
end

def has_plan?(plan_name)
plan.name == plan_name.to_s
end
Expand Down
17 changes: 12 additions & 5 deletions rails/app/views/devise/registrations/edit.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -5,19 +5,26 @@
.form-group
=render 'devise/shared/error_messages', resource: resource

.form-group
=f.label :name
=f.text_field :name, autofocus: true, autofill: 'off', autocomplete: 'off', class: 'form-control col-sm-6'

.form-group
=f.label :email
=f.email_field :email, autocomplete: 'email', class: 'form-control col-sm-6'
=f.email_field :email, autocomplete: true, autocomplete: 'email', class: 'form-control col-sm-6'
%small.form-text.text-muted Your email address

-if devise_mapping.confirmable? && resource.pending_reconfirmation?
%small.form-text.text-muted
Currently waiting confirmation for:
=resource.unconfirmed_email

.form-group
=f.label :name
=f.text_field :name, autofocus: true, autofill: 'off', autocomplete: 'off', class: 'form-control col-sm-6'
%small.form-text.text-muted Your name

.form-group
= f.label :username
= f.text_field :username, autofocus: true, autofill: 'off', autocomplete: 'off', class: 'form-control col-sm-6'
%small.form-text.text-muted Unique username (optional)

.form-group
=gravatar_image(resource)
%div.form-group
Expand Down
13 changes: 9 additions & 4 deletions rails/app/views/devise/registrations/new.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,20 @@
.form-group
=render 'devise/shared/error_messages', resource: resource

.form-group
= f.label :email
= f.email_field :email, autofocus: true, autocomplete: 'email', class: 'form-control col-sm-6'
%small.form-text.text-muted Enter your email address

.form-group
= f.label :name
= f.text_field :name, autofocus: true, autofill: 'off', autocomplete: 'off', class: 'form-control col-sm-6'
= f.text_field :name, autofill: 'off', autocomplete: 'off', class: 'form-control col-sm-6'
%small.form-text.text-muted Please enter your name

.form-group
= f.label :email
= f.email_field :email, autocomplete: 'email', class: 'form-control col-sm-6'
%small.form-text.text-muted Enter your email address
= f.label :username
= f.text_field :username, autofocus: true, autofill: 'off', autocomplete: 'off', class: 'form-control col-sm-6'
%small.form-text.text-muted Optional. Choose a unique username between 3 and 30 characters long.

.form-group
= f.label :password
Expand Down
36 changes: 28 additions & 8 deletions rails/app/views/hub/index.html.haml
Original file line number Diff line number Diff line change
@@ -1,14 +1,28 @@

%h1= @title || bi_icon(:tag) + @tag
%h1
- if @tag.present?
= bi_icon('tag') + @tag
- elsif @user.present?
- if @user.use_gravatar?
= gravatar_image(@user, size: 35) + @user.name
- else
= bi_icon('person-fill') + @user.name
- else
Tiddlyhost Hub

%p.text-muted{style: 'font-size: 95%'}
= @tag_description
- if @tag.present?
Sites tagged with
%b= @tag + '.'
- elsif @user.present?
Sites created by Tiddlyhost user
%b= @user.username + '.'
- else
If you mark your site as 'Searchable' it will be listed here.

%div{style: "margin-bottom: 2em;"}
%ul.nav.nav-tabs
= hub_link_to('All sites', '/hub')
- @hub_tags.each do |k, tag_info|
= hub_link_to(tag_info[:title], "/hub/#{k}")
- @tag_tabs.each do |tag|
= hub_tag_link_to(tag)
Expand All @@ -35,15 +49,21 @@

.hub
- @sites.each do |s|
.site
.site{id: s.name}
.name
= site_long_link s
.description
= span_with_title_truncated(s.description)
.owner
%span Owner:
= gravatar_image(s.user, size: 16) if s.user.use_gravatar?
= s.user.name
- if s.user.use_gravatar?
= gravatar_image(s.user, size: 14) if s.user.use_gravatar?
- else
= bi_icon('person-fill', style: 'margin-right:-3px;')
- if s.user.username.present?
%span{title: s.user.name}
= link_to s.user.username, "/hub/user/#{s.user.username}"
- else
= s.user.name
%span{style: 'margin-left: 0.5em;'} Views:
= s.view_count
- unless s.tag_list.empty?
Expand Down
2 changes: 1 addition & 1 deletion rails/app/views/layouts/_header.html.erb
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
<%= nav_link_to "Sites", admin_sites_path %>
<%= nav_link_to "Users", admin_users_path %>
<% end %>
<%= nav_link_to current_user.name, edit_user_registration_path, icon: 'person-fill' %>
<%= nav_link_to current_user.username_or_name, edit_user_registration_path, icon: 'person-fill' %>
<%= nav_link_to "Log out", destroy_user_session_path, method: :delete, icon: 'box-arrow-left' %>
</ul>
<% else %>
Expand Down
2 changes: 1 addition & 1 deletion rails/config/initializers/app_version.rb
Original file line number Diff line number Diff line change
@@ -1 +1 @@
App::VERSION = '0.0.3'
App::VERSION = '0.0.4'
2 changes: 1 addition & 1 deletion rails/config/initializers/devise.rb
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@
# Configure which authentication keys should have whitespace stripped.
# These keys will have whitespace before and after removed upon creating or
# modifying a user and when used to authenticate or find a user. Default is :email.
config.strip_whitespace_keys = [:email, :name]
config.strip_whitespace_keys = [:email, :name, :username]

# Tell if authentication through request.params is enabled. True by default.
# It can be set to an array that will enable params authentication only for the
Expand Down
Loading

0 comments on commit 6f1c541

Please sign in to comment.