Exclude:
- 'app/controllers/application_controller.rb'
- 'app/controllers/confirmations_controller.rb'
- - 'app/controllers/friendships_controller.rb'
- 'app/controllers/issue_comments_controller.rb'
- 'app/controllers/messages_controller.rb'
- 'app/controllers/passwords_controller.rb'
Exclude:
- 'app/models/changeset.rb'
- 'app/models/diary_entry.rb'
- - 'app/models/friendship.rb'
- 'app/models/issue.rb'
- 'app/models/message.rb'
- 'app/models/note.rb'
can [:create, :update], :password
can :read, Redaction
can [:create, :destroy], :session
- can [:read, :data, :georss], Trace
+ can [:read, :data], Trace
can [:read, :create, :suspended, :auth_success, :auth_failure], User
can :read, UserBlock
end
can [:create, :subscribe, :unsubscribe], DiaryEntry
can :update, DiaryEntry, :user => user
can [:create], DiaryComment
- can [:make_friend, :remove_friend], Friendship
+ can [:show, :create, :destroy], Follow
can [:read, :create, :mark, :unmute, :destroy], Message
can [:close, :reopen], Note
can [:read, :update], :preference
can [:hide, :unhide], [DiaryEntry, DiaryComment]
can [:read, :resolve, :ignore, :reopen], Issue
can :create, IssueComment
- can [:set_status, :destroy], User
+
+ can [:update], :user_status
can [:read, :update], :users_list
can [:create, :destroy], UserRole
end
layerOptions.apikey = OSM[value];
} else if (property === "leafletOsmId") {
layerConstructor = L.OSM[value];
+ } else if (property === "leafletOsmDarkId" && OSM.isDarkMap() && L.OSM[value]) {
+ layerConstructor = L.OSM[value];
} else {
layerOptions[property] = value;
}
}
});
+OSM.isDarkMap = function () {
+ var mapTheme = $("body").attr("data-map-theme");
+ if (mapTheme) return mapTheme === "dark";
+ var siteTheme = $("html").attr("data-bs-theme");
+ if (siteTheme) return siteTheme === "dark";
+ return window.matchMedia("(prefers-color-scheme: dark)").matches;
+};
+
OSM.getUserIcon = function (url) {
return L.icon({
iconUrl: url || OSM.MARKER_RED,
body {
font-size: $typeheight;
- --dark-mode-map-filter: brightness(.8);
+ --dark-mode-map-filter: none;
}
time[title] {
elsif @params[:bbox]
changesets = conditions_bbox(changesets, BoundingBox.from_bbox_params(params))
elsif @params[:friends] && current_user
- changesets = changesets.where(:user => current_user.friends.identifiable)
+ changesets = changesets.where(:user => current_user.followings.identifiable)
elsif @params[:nearby] && current_user
changesets = changesets.where(:user => current_user.nearby)
end
end
elsif params[:friends]
if current_user
- @title = t ".title_friends"
- entries = DiaryEntry.where(:user => current_user.friends)
+ @title = t ".title_followed"
+ entries = DiaryEntry.where(:user => current_user.followings)
else
require_user
return
--- /dev/null
+class FollowsController < ApplicationController
+ include UserMethods
+
+ layout "site"
+
+ before_action :authorize_web
+ before_action :set_locale
+ before_action :check_database_readable
+
+ authorize_resource
+
+ before_action :check_database_writable
+ before_action :lookup_user
+
+ def show
+ @already_follows = current_user.follows?(@user)
+ end
+
+ def create
+ follow = Follow.new
+ follow.follower = current_user
+ follow.following = @user
+ if current_user.follows?(@user)
+ flash[:warning] = t ".already_followed", :name => @user.display_name
+ elsif current_user.follows.where(:created_at => Time.now.utc - 1.hour..).count >= current_user.max_follows_per_hour
+ flash[:error] = t ".limit_exceeded"
+ elsif follow.save
+ flash[:notice] = t ".success", :name => @user.display_name
+ UserMailer.follow_notification(follow).deliver_later
+ else
+ follow.add_error(t(".failed", :name => @user.display_name))
+ end
+
+ referer = safe_referer(params[:referer]) if params[:referer]
+
+ redirect_to referer || user_path
+ end
+
+ def destroy
+ if current_user.follows?(@user)
+ Follow.where(:follower => current_user, :following => @user).delete_all
+ flash[:notice] = t ".success", :name => @user.display_name
+ else
+ flash[:error] = t ".not_followed", :name => @user.display_name
+ end
+
+ referer = safe_referer(params[:referer]) if params[:referer]
+
+ redirect_to referer || user_path
+ end
+end
+++ /dev/null
-class FriendshipsController < ApplicationController
- include UserMethods
-
- layout "site"
-
- before_action :authorize_web
- before_action :set_locale
- before_action :check_database_readable
-
- authorize_resource
-
- before_action :check_database_writable, :only => [:make_friend, :remove_friend]
- before_action :lookup_friend, :only => [:make_friend, :remove_friend]
-
- def make_friend
- if request.post?
- friendship = Friendship.new
- friendship.befriender = current_user
- friendship.befriendee = @friend
- if current_user.friends_with?(@friend)
- flash[:warning] = t ".already_a_friend", :name => @friend.display_name
- elsif current_user.friendships.where(:created_at => Time.now.utc - 1.hour..).count >= current_user.max_friends_per_hour
- flash[:error] = t ".limit_exceeded"
- elsif friendship.save
- flash[:notice] = t ".success", :name => @friend.display_name
- UserMailer.friendship_notification(friendship).deliver_later
- else
- friendship.add_error(t(".failed", :name => @friend.display_name))
- end
-
- referer = safe_referer(params[:referer]) if params[:referer]
-
- redirect_to referer || user_path
- end
- end
-
- def remove_friend
- if request.post?
- if current_user.friends_with?(@friend)
- Friendship.where(:befriender => current_user, :befriendee => @friend).delete_all
- flash[:notice] = t ".success", :name => @friend.display_name
- else
- flash[:error] = t ".not_a_friend", :name => @friend.display_name
- end
-
- referer = safe_referer(params[:referer]) if params[:referer]
-
- redirect_to referer || user_path
- end
- end
-
- private
-
- ##
- # ensure that there is a "friend" instance variable
- def lookup_friend
- @friend = User.active.find_by!(:display_name => params[:display_name])
- rescue ActiveRecord::RecordNotFound
- render_unknown_user params[:display_name]
- end
-end
--- /dev/null
+module Traces
+ class FeedsController < ApplicationController
+ before_action :authorize_web
+ before_action :set_locale
+ before_action :check_database_readable
+
+ authorize_resource :class => Trace
+
+ def show
+ @traces = Trace.visible_to_all.visible
+
+ @traces = @traces.joins(:user).where(:users => { :display_name => params[:display_name] }) if params[:display_name]
+
+ @traces = @traces.tagged(params[:tag]) if params[:tag]
+ @traces = @traces.order("timestamp DESC")
+ @traces = @traces.limit(20)
+ @traces = @traces.includes(:user)
+ end
+ end
+end
include UserMethods
include PaginationMethods
- layout "site", :except => :georss
+ layout "site"
before_action :authorize_web
before_action :set_locale
head :not_found
end
- def georss
- @traces = Trace.visible_to_all.visible
-
- @traces = @traces.joins(:user).where(:users => { :display_name => params[:display_name] }) if params[:display_name]
-
- @traces = @traces.tagged(params[:tag]) if params[:tag]
- @traces = @traces.order("timestamp DESC")
- @traces = @traces.limit(20)
- @traces = @traces.includes(:user)
- end
-
private
def do_create(file, tags, description, visibility)
--- /dev/null
+module Users
+ class StatusesController < ApplicationController
+ layout "site"
+
+ before_action :authorize_web
+ before_action :set_locale
+ before_action :check_database_readable
+
+ authorize_resource :class => :user_status
+
+ before_action :lookup_user_by_name
+
+ ##
+ # sets a user's status
+ def update
+ @user.activate! if params[:event] == "activate"
+ @user.confirm! if params[:event] == "confirm"
+ @user.unconfirm! if params[:event] == "unconfirm"
+ @user.hide! if params[:event] == "hide"
+ @user.unhide! if params[:event] == "unhide"
+ @user.unsuspend! if params[:event] == "unsuspend"
+ @user.soft_destroy! if params[:event] == "soft_destroy" # destroy a user, marking them as deleted and removing personal data
+ redirect_to user_path(params[:user_display_name])
+ end
+
+ private
+
+ ##
+ # ensure that there is a "user" instance variable
+ def lookup_user_by_name
+ @user = User.find_by!(:display_name => params[:user_display_name])
+ rescue ActiveRecord::RecordNotFound
+ redirect_to user_path(params[:user_display_name]) unless @user
+ end
+ end
+end
before_action :check_database_writable, :only => [:new, :go_public]
before_action :require_cookies, :only => [:new]
- before_action :lookup_user_by_name, :only => [:set_status, :destroy]
allow_thirdparty_images :only => :show
allow_social_login :only => :new
end
end
- ##
- # destroy a user, marking them as deleted and removing personal data
- def destroy
- @user.soft_destroy!
- redirect_to user_path(:display_name => params[:display_name])
- end
-
def go_public
current_user.data_public = true
current_user.save
redirect_to edit_account_path
end
- ##
- # sets a user's status
- def set_status
- @user.activate! if params[:event] == "activate"
- @user.confirm! if params[:event] == "confirm"
- @user.unconfirm! if params[:event] == "unconfirm"
- @user.hide! if params[:event] == "hide"
- @user.unhide! if params[:event] == "unhide"
- @user.unsuspend! if params[:event] == "unsuspend"
- redirect_to user_path(:display_name => params[:display_name])
- end
-
##
# omniauth success callback
def auth_success
end
end
- ##
- # ensure that there is a "user" instance variable
- def lookup_user_by_name
- @user = User.find_by(:display_name => params[:display_name])
- rescue ActiveRecord::RecordNotFound
- redirect_to :action => "view", :display_name => params[:display_name] unless @user
- end
-
##
# return permitted user parameters
def user_params
def changeset_index_title(params, user)
if params[:friends] && user
- t "changesets.index.title_friend"
+ t "changesets.index.title_followed"
elsif params[:nearby] && user
t "changesets.index.title_nearby"
elsif params[:display_name]
end
end
- def friendship_notification(friendship)
- with_recipient_locale friendship.befriendee do
- @friendship = friendship
- @viewurl = user_url(@friendship.befriender)
- @friendurl = make_friend_url(@friendship.befriender)
- @author = @friendship.befriender.display_name
-
- attach_user_avatar(@friendship.befriender)
- mail :to => friendship.befriendee.email,
- :subject => t(".subject", :user => friendship.befriender.display_name)
+ def follow_notification(follow)
+ with_recipient_locale follow.following do
+ @follow = follow
+ @viewurl = user_url(@follow.follower)
+ @followurl = follow_url(@follow.follower)
+ @author = @follow.follower.display_name
+
+ attach_user_avatar(@follow.follower)
+ mail :to => follow.following.email,
+ :subject => t(".subject", :user => follow.follower.display_name)
end
end
# friends_user_id_fkey (user_id => users.id)
#
-class Friendship < ApplicationRecord
+class Follow < ApplicationRecord
self.table_name = "friends"
- belongs_to :befriender, :class_name => "User", :foreign_key => :user_id
- belongs_to :befriendee, :class_name => "User", :foreign_key => :friend_user_id
+ belongs_to :follower, :class_name => "User", :foreign_key => :user_id, :inverse_of => :follows
+ belongs_to :following, :class_name => "User", :foreign_key => :friend_user_id, :inverse_of => :follows
end
has_many :new_messages, -> { where(:to_user_visible => true, :muted => false, :message_read => false).order(:sent_on => :desc) }, :class_name => "Message", :foreign_key => :to_user_id
has_many :sent_messages, -> { where(:from_user_visible => true).order(:sent_on => :desc).preload(:sender, :recipient) }, :class_name => "Message", :foreign_key => :from_user_id
has_many :muted_messages, -> { where(:to_user_visible => true, :muted => true).order(:sent_on => :desc).preload(:sender, :recipient) }, :class_name => "Message", :foreign_key => :to_user_id
- has_many :friendships, -> { joins(:befriendee).where(:users => { :status => %w[active confirmed] }) }
- has_many :friends, :through => :friendships, :source => :befriendee
+ has_many :follows, -> { joins(:following).where(:users => { :status => %w[active confirmed] }) }
+ has_many :followings, :through => :follows, :source => :following
has_many :preferences, :class_name => "UserPreference"
has_many :changesets, -> { order(:created_at => :desc) }, :inverse_of => :user
has_many :changeset_comments, :foreign_key => :author_id, :inverse_of => :author
OSM::GreatCircle.new(home_lat, home_lon).distance(nearby_user.home_lat, nearby_user.home_lon)
end
- def friends_with?(new_friend)
- friendships.exists?(:befriendee => new_friend)
+ def follows?(user)
+ follows.exists?(:following => user)
end
##
max_messages.clamp(0, Settings.max_messages_per_hour)
end
- def max_friends_per_hour
+ def max_follows_per_hour
account_age_in_seconds = Time.now.utc - created_at
account_age_in_hours = account_age_in_seconds / 3600
- recent_friends = Friendship.where(:befriendee => self).where(:created_at => Time.now.utc - 3600..).count
- max_friends = account_age_in_hours.ceil + recent_friends - (active_reports * 10)
- max_friends.clamp(0, Settings.max_friends_per_hour)
+ recent_follows = Follow.where(:following => self).where(:created_at => Time.now.utc - 3600..).count
+ max_follows = account_age_in_hours.ceil + recent_follows - (active_reports * 10)
+ max_follows.clamp(0, Settings.max_follows_per_hour)
end
def max_changeset_comments_per_hour
<small class="form-text text-body-secondary">(<a href="<%= t ".openid.link" %>" target="_new"><%= t ".openid.link text" %></a>)</small>
</fieldset>
- <div class="mb-3">
- <label class="form-label"><%= t ".public editing.heading" %></label>
- <span class="form-text text-body-secondary">
- <% if current_user.data_public? %>
- <%= t ".public editing.enabled" %>
- (<a href="<%= t ".public editing.enabled link" %>" target="_new"><%= t ".public editing.enabled link text" %></a>)
- <% else %>
- <%= t ".public editing.disabled" %>
- (<a href="#public"><%= t ".public editing.disabled link text" %></a>)
- <% end %>
- </span>
- </div>
-
<div class="mb-3">
<label class="form-label"><%= t ".contributor terms.heading" %></label>
<span class="form-text text-body-secondary">
json.title message.title
json.sent_on message.sent_on.xmlschema
+json.message_read message.message_read if current_user.id == message.to_user_id
+
if current_user.id == message.from_user_id
json.deleted !message.from_user_visible
elsif current_user.id == message.to_user_id
- json.message_read message.message_read
json.deleted !message.to_user_visible
end
"body_format" => message.body_format
}
+attrs["message_read"] = message.message_read if current_user.id == message.to_user_id
+
if current_user.id == message.from_user_id
attrs["deleted"] = !message.from_user_visible
elsif current_user.id == message.to_user_id
- attrs["message_read"] = message.message_read
attrs["deleted"] = !message.to_user_visible
end
<% user_data = {
:lon => contact.home_lon,
:lat => contact.home_lat,
- :icon => image_path(type == "friend" ? "marker-blue.png" : "marker-green.png"),
+ :icon => image_path(type == "following" ? "marker-blue.png" : "marker-green.png"),
:description => render(:partial => "popup", :object => contact, :locals => { :type => type })
} %>
<%= tag.div :class => "clearfix row", :data => { :user => user_data } do %>
<ul class='clearfix text-body-secondary'>
<li><%= link_to t("users.show.send message"), new_message_path(contact) %></li>
<li>
- <% if current_user.friends_with?(contact) %>
- <%= link_to t("users.show.remove as friend"), remove_friend_path(:display_name => contact.display_name, :referer => request.fullpath), :method => :post %>
+ <% if current_user.follows?(contact) %>
+ <%= link_to t("users.show.unfollow"), follow_path(:display_name => contact.display_name, :referer => request.fullpath), :method => :delete %>
<% else %>
- <%= link_to t("users.show.add as friend"), make_friend_path(:display_name => contact.display_name, :referer => request.fullpath), :method => :post %>
+ <%= link_to t("users.show.follow"), follow_path(:display_name => contact.display_name, :referer => request.fullpath), :method => :post %>
<% end %>
</li>
</ul>
<%= tag.div "", :id => "map", :class => "content_map border border-secondary-subtle rounded z-0", :data => { :user => user_data } %>
<% end %>
- <% friends = @user.friends %>
- <% nearby = @user.nearby - friends %>
+ <% followings = @user.followings %>
+ <% nearby = @user.nearby - followings %>
</div>
<div class="col-md">
- <h2><%= t ".my friends" %></h2>
+ <h2><%= t ".followings" %></h2>
- <% if friends.empty? %>
- <%= t ".no friends" %>
+ <% if followings.empty? %>
+ <%= t ".no followings" %>
<% else %>
<nav class='secondary-actions mb-3'>
<ul class='clearfix'>
- <li><%= link_to t(".friends_changesets"), friend_changesets_path %></li>
- <li><%= link_to t(".friends_diaries"), friends_diary_entries_path %></li>
+ <li><%= link_to t(".followed_changesets"), friend_changesets_path %></li>
+ <li><%= link_to t(".followed_diaries"), friends_diary_entries_path %></li>
</ul>
</nav>
<div>
- <%= render :partial => "contact", :collection => friends, :locals => { :type => "friend" } %>
+ <%= render :partial => "contact", :collection => followings, :locals => { :type => "following" } %>
</div>
<% end %>
--- /dev/null
+<% content_for :heading do %>
+ <h1><%= t(@already_follows ? ".unfollow.heading" : ".follow.heading", :user => @user.display_name) %></h1>
+<% end %>
+
+<%= bootstrap_form_tag :method => (@already_follows ? :delete : :post) do |f| %>
+ <% if params[:referer] -%>
+ <%= f.hidden_field :referer, :value => params[:referer] %>
+ <% end -%>
+ <%= f.primary @already_follows ? t(".unfollow.button") : t(".follow.button") %>
+<% end %>
+++ /dev/null
-<% content_for :heading do %>
- <h1><%= t ".heading", :user => @friend.display_name %></h1>
-<% end %>
-
-<%= bootstrap_form_tag do |f| %>
- <% if params[:referer] -%>
- <%= f.hidden_field :referer, :value => params[:referer] %>
- <% end -%>
- <%= f.primary t(".button") %>
-<% end %>
+++ /dev/null
-<% content_for :heading do %>
- <h1><%= t ".heading", :user => @friend.display_name %></h1>
-<% end %>
-
-<%= bootstrap_form_tag do |f| %>
- <% if params[:referer] -%>
- <%= f.hidden_field :referer, :value => params[:referer] %>
- <% end -%>
- <%= f.primary t(".button") %>
-<% end %>
xml.channel do
xml.title t(".title")
xml.description t(".title")
- xml.link url_for(:controller => :traces, :action => :index, :only_path => false)
+ xml.link url_for(:controller => "/traces", :action => :index, :only_path => false)
xml.image do
xml.url image_url("mag_map-rss2.0.png")
xml.title t(".title")
xml.width 100
xml.height 100
- xml.link url_for(:controller => :traces, :action => :index, :only_path => false)
+ xml.link url_for(:controller => "/traces", :action => :index, :only_path => false)
end
@traces.each do |trace|
<div class="d-flex flex-column flex-md-row-reverse align-items-md-end">
<div class="pb-1 ps-1 d-flex flex-wrap flex-shrink-0 gap-1 justify-content-end">
- <%= link_to({ :action => :georss, :display_name => @target_user&.display_name, :tag => params[:tag] },
- { :class => "btn btn-secondary btn-sm" }) do %>
+ <%= link_to traces_feed_path(:display_name => @target_user&.display_name, :tag => params[:tag]),
+ :class => "btn btn-secondary btn-sm" do %>
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" class="align-text-bottom">
<circle cx="2" cy="14" r="2" fill="white" />
<path d="M 8 14 a 6 6 0 0 0 -6 -6 M 14 14 a 12 12 0 0 0 -12 -12" fill="none" stroke="white" stroke-width="3" stroke-linecap="round" />
<% end %>
<% content_for :auto_discovery_link_tag do %>
- <%= auto_discovery_link_tag :rss, :action => "georss", :display_name => @target_user&.display_name, :tag => params[:tag] %>
+ <%= auto_discovery_link_tag :rss, traces_feed_path(:display_name => @target_user&.display_name, :tag => params[:tag]) %>
<% end %>
<% if @traces.size > 0 %>
--- /dev/null
+<p><%= t ".hi", :to_user => @follow.following.display_name %></p>
+
+<p><%= t ".followed_you", :user => @follow.follower.display_name %></p>
+
+<%= message_body do %>
+ <p><%= t ".see_their_profile_html", :userurl => link_to(@viewurl, @viewurl) %></p>
+
+ <% unless @follow.following.follows?(@follow.follower) -%>
+ <p><%= t ".follow_them_html", :followurl => link_to(@followurl, @followurl) %></p>
+ <% end -%>
+<% end %>
--- /dev/null
+<%= t ".hi", :to_user => @follow.following.display_name %>
+
+<%= t '.followed_you', :user => @follow.follower.display_name %>
+
+<%= t '.see_their_profile', :userurl => @viewurl %>
+
+<% unless @follow.following.follows?(@follow.follower) -%>
+<%= t '.follow_them', :followurl => @followurl %>
+<% end -%>
+++ /dev/null
-<p><%= t ".hi", :to_user => @friendship.befriendee.display_name %></p>
-
-<p><%= t ".had_added_you", :user => @friendship.befriender.display_name %></p>
-
-<%= message_body do %>
- <p><%= t ".see_their_profile_html", :userurl => link_to(@viewurl, @viewurl) %></p>
-
- <% unless @friendship.befriendee.friends_with?(@friendship.befriender) -%>
- <p><%= t ".befriend_them_html", :befriendurl => link_to(@friendurl, @friendurl) %></p>
- <% end -%>
-<% end %>
+++ /dev/null
-<%= t ".hi", :to_user => @friendship.befriendee.display_name %>
-
-<%= t '.had_added_you', :user => @friendship.befriender.display_name %>
-
-<%= t '.see_their_profile', :userurl => @viewurl %>
-
-<% unless @friendship.befriendee.friends_with?(@friendship.befriender) -%>
-<%= t '.befriend_them', :befriendurl => @friendurl %>
-<% end -%>
</li>
<% if current_user %>
<li>
- <% if current_user.friends_with?(@user) %>
- <%= link_to t(".remove as friend"), remove_friend_path(:display_name => @user.display_name), :method => :post %>
+ <% if current_user.follows?(@user) %>
+ <%= link_to t(".unfollow"), follow_path(:display_name => @user.display_name), :method => :delete %>
<% else %>
- <%= link_to t(".add as friend"), make_friend_path(:display_name => @user.display_name), :method => :post %>
+ <%= link_to t(".follow"), follow_path(:display_name => @user.display_name), :method => :post %>
<% end %>
</li>
<% end %>
</small>
</div>
- <% if can?(:set_status, User) || can?(:destroy, User) %>
+ <% if can?(:update, :user_status) %>
<nav class='secondary-actions'>
<ul class='clearfix'>
- <% if can? :set_status, User %>
- <% if @user.may_activate? %>
- <li>
- <%= link_to t(".activate_user"), set_status_user_path(:event => "activate", :display_name => @user.display_name), :method => :post, :data => { :confirm => t(".confirm") } %>
- </li>
- <% end %>
-
- <% if @user.may_unsuspend? %>
- <li>
- <%= link_to t(".unsuspend_user"), set_status_user_path(:event => "unsuspend", :display_name => @user.display_name), :method => :post, :data => { :confirm => t(".confirm") } %>
- </li>
- <% end %>
-
- <% if @user.may_confirm? %>
- <li>
- <%= link_to t(".confirm_user"), set_status_user_path(:event => "confirm", :display_name => @user.display_name), :method => :post, :data => { :confirm => t(".confirm") } %>
- </li>
- <% end %>
-
- <% if @user.may_unconfirm? %>
- <li>
- <%= link_to t(".unconfirm_user"), set_status_user_path(:event => "unconfirm", :display_name => @user.display_name), :method => :post, :data => { :confirm => t(".confirm") } %>
- </li>
- <% end %>
-
- <% if @user.may_hide? %>
- <li>
- <%= link_to t(".hide_user"), set_status_user_path(:event => "hide", :display_name => @user.display_name), :method => :post, :data => { :confirm => t(".confirm") } %>
- </li>
- <% end %>
-
- <% if @user.may_unhide? %>
- <li>
- <%= link_to t(".unhide_user"), set_status_user_path(:event => "unhide", :display_name => @user.display_name), :method => :post, :data => { :confirm => t(".confirm") } %>
- </li>
- <% end %>
- <% end %>
-
- <% if can?(:destroy, User) && @user.may_soft_destroy? %>
- <li>
- <%= link_to t(".delete_user"), user_path(:display_name => @user.display_name), :method => :delete, :data => { :confirm => t(".confirm") } %>
+ <% if @user.may_activate? %>
+ <li>
+ <%= link_to t(".activate_user"), user_status_path(@user, :event => "activate"), :method => :put, :data => { :confirm => t(".confirm") } %>
+ </li>
+ <% end %>
+
+ <% if @user.may_unsuspend? %>
+ <li>
+ <%= link_to t(".unsuspend_user"), user_status_path(@user, :event => "unsuspend"), :method => :put, :data => { :confirm => t(".confirm") } %>
+ </li>
+ <% end %>
+
+ <% if @user.may_confirm? %>
+ <li>
+ <%= link_to t(".confirm_user"), user_status_path(@user, :event => "confirm"), :method => :put, :data => { :confirm => t(".confirm") } %>
+ </li>
+ <% end %>
+
+ <% if @user.may_unconfirm? %>
+ <li>
+ <%= link_to t(".unconfirm_user"), user_status_path(@user, :event => "unconfirm"), :method => :put, :data => { :confirm => t(".confirm") } %>
+ </li>
+ <% end %>
+
+ <% if @user.may_hide? %>
+ <li>
+ <%= link_to t(".hide_user"), user_status_path(@user, :event => "hide"), :method => :put, :data => { :confirm => t(".confirm") } %>
+ </li>
+ <% end %>
+
+ <% if @user.may_unhide? %>
+ <li>
+ <%= link_to t(".unhide_user"), user_status_path(@user, :event => "unhide"), :method => :put, :data => { :confirm => t(".confirm") } %>
+ </li>
+ <% end %>
+
+ <% if @user.may_soft_destroy? %>
+ <li>
+ <%= link_to t(".delete_user"), user_status_path(@user, :event => "soft_destroy"), :method => :put, :data => { :confirm => t(".confirm") } %>
</li>
<% end %>
</ul>
href: "https://www.thunderforest.com/"
- leafletOsmId: "TransportMap"
+ leafletOsmDarkId: "TransportDarkMap"
code: "T"
layerId: "transportmap"
nameId: "transport_map"
support_url: Support URL
allow_read_prefs: read their user preferences
allow_write_prefs: modify their user preferences
- allow_write_diary: create diary entries, comments and make friends
+ allow_write_diary: create diary entries and comments
allow_write_api: modify the map
allow_read_gpx: read their private GPS traces
allow_write_gpx: upload GPS traces
openid:
link: "https://wiki.openstreetmap.org/wiki/OpenID"
link text: "what is this?"
- public editing:
- heading: "Public editing"
- enabled: "Enabled. Not anonymous and can edit data."
- enabled link: "https://wiki.openstreetmap.org/wiki/Anonymous_edits"
- enabled link text: "what is this?"
- disabled: "Disabled and cannot edit data, all previous edits are anonymous."
- disabled link text: "why can't I edit?"
contributor terms:
heading: "Contributor Terms"
agreed: "You have agreed to the new Contributor Terms."
title: "Changesets"
title_user: "Changesets by %{user}"
title_user_link_html: "Changesets by %{user_link}"
- title_friend: "Changesets by my friends"
+ title_followed: "Changesets by followings"
title_nearby: "Changesets by nearby users"
empty: "No changesets found."
empty_area: "No changesets in this area."
popup:
your location: "Your location"
nearby mapper: "Nearby mapper"
- friend: "Friend"
+ following: "Following"
show:
title: My Dashboard
no_home_location_html: "%{edit_profile_link} and set your home location to see nearby users."
edit_your_profile: Edit your profile
- my friends: My friends
- no friends: You have not added any friends yet.
+ followings: Followings
+ no followings: You have not followed any user yet.
nearby users: "Other nearby users"
no nearby users: "There are no other users who admit to mapping nearby yet."
- friends_changesets: "friends' changesets"
- friends_diaries: "friends' diary entries"
+ followed_changesets: "changesets"
+ followed_diaries: "diary entries"
nearby_changesets: "nearby user changesets"
nearby_diaries: "nearby user diary entries"
diary_entries:
use_map_link: Use Map
index:
title: "Users' Diaries"
- title_friends: "Friends' Diaries"
+ title_followed: "Followings' Diaries"
title_nearby: "Nearby Users' Diaries"
user_title: "%{user}'s Diary"
in_language_title: "Diary Entries in %{language}"
not_found:
title: File not found
description: Couldn't find a file/directory/API operation by that name on the OpenStreetMap server (HTTP 404)
- friendships:
- make_friend:
- heading: "Add %{user} as a friend?"
- button: "Add as friend"
- success: "%{name} is now your friend!"
- failed: "Sorry, failed to add %{name} as a friend."
- already_a_friend: "You are already friends with %{name}."
- limit_exceeded: "You have friended a lot of users recently. Please wait a while before trying to friend any more."
- remove_friend:
- heading: "Unfriend %{user}?"
- button: "Unfriend"
- success: "%{name} was removed from your friends."
- not_a_friend: "%{name} is not one of your friends."
+ follows:
+ show:
+ follow:
+ heading: "Do you want to follow %{user}?"
+ button: "Follow User"
+ unfollow:
+ heading: "Do you want to unfollow %{user}?"
+ button: "Unfollow User"
+ create:
+ success: "You are now following %{name}!"
+ failed: "Sorry, your request to follow %{name} has failed."
+ already_followed: "You already follow %{name}."
+ limit_exceeded: "You have followed a lot of users recently. Please wait a while before trying to follow any more."
+ destroy:
+ success: "You successfully unfollowed %{name}."
+ not_followed: "You are not following %{name}."
geocoder:
search:
title:
header_html: "%{from_user} has sent you a message through OpenStreetMap with the subject %{subject}:"
footer: "You can also read the message at %{readurl} and you can send a message to the author at %{replyurl}"
footer_html: "You can also read the message at %{readurl} and you can send a message to the author at %{replyurl}"
- friendship_notification:
+ follow_notification:
hi: "Hi %{to_user},"
- subject: "[OpenStreetMap] %{user} added you as a friend"
- had_added_you: "%{user} has added you as a friend on OpenStreetMap."
+ subject: "[OpenStreetMap] %{user} followed you"
+ followed_you: "%{user} is now following you on OpenStreetMap."
see_their_profile: "You can see their profile at %{userurl}."
see_their_profile_html: "You can see their profile at %{userurl}."
- befriend_them: "You can also add them as a friend at %{befriendurl}."
- befriend_them_html: "You can also add them as a friend at %{befriendurl}."
+ follow_them: "You can also follow them at %{followurl}."
+ follow_them_html: "You can also follow them at %{followurl}."
gpx_details:
details: "Your file details:"
filename: Filename
offline:
heading: "GPX Storage Offline"
message: "The GPX file storage and upload system is currently unavailable."
- georss:
- title: "OpenStreetMap GPS Traces"
- description:
- description_with_count:
- one: "GPX file with %{count} point from %{user}"
- other: "GPX file with %{count} points from %{user}"
- description_without_count: "GPX file from %{user}"
+ feeds:
+ show:
+ title: "OpenStreetMap GPS Traces"
+ description:
+ description_with_count:
+ one: "GPX file with %{count} point from %{user}"
+ other: "GPX file with %{count} points from %{user}"
+ description_without_count: "GPX file from %{user}"
application:
permission_denied: You do not have permission to access that action
require_cookies:
openid: Sign-in using OpenStreetMap
read_prefs: Read user preferences
write_prefs: Modify user preferences
- write_diary: Create diary entries, comments and make friends
+ write_diary: Create diary entries and comments
write_api: Modify the map
read_gpx: Read private GPS traces
write_gpx: Upload GPS traces
edits: Edits
traces: Traces
notes: Map Notes
- remove as friend: Unfriend
- add as friend: Add Friend
+ unfollow: Unfollow
+ follow: Follow
mapper since: "Mapper since:"
last map edit: "Last map edit:"
no activity yet: "No activity yet"
get "relations" => "relations#index"
get "map" => "map#index"
-
- get "trackpoints" => "tracepoints#index"
end
namespace :api, :path => "api/0.6" do
+ resources :tracepoints, :path => "trackpoints", :only => :index
+
resources :users, :only => :index
resources :users, :path => "user", :id => /\d+/, :only => :show
resources :user_traces, :path => "user/gpx_files", :module => :users, :controller => :traces, :only => :index
post "/preview/:type" => "site#preview", :as => :preview
# traces
- resources :traces, :except => [:show]
+ resources :traces, :id => /\d+/, :except => [:show]
get "/user/:display_name/traces/tag/:tag/page/:page", :page => /[1-9][0-9]*/, :to => redirect(:path => "/user/%{display_name}/traces/tag/%{tag}")
get "/user/:display_name/traces/tag/:tag" => "traces#index"
get "/user/:display_name/traces/page/:page", :page => /[1-9][0-9]*/, :to => redirect(:path => "/user/%{display_name}/traces")
get "/user/:display_name/traces" => "traces#index"
- get "/user/:display_name/traces/tag/:tag/rss" => "traces#georss", :defaults => { :format => :rss }
- get "/user/:display_name/traces/rss" => "traces#georss", :defaults => { :format => :rss }
- get "/user/:display_name/traces/:id" => "traces#show", :as => "show_trace"
- scope "/user/:display_name/traces/:trace_id", :module => :traces do
+ get "/user/:display_name/traces/:id" => "traces#show", :id => /\d+/, :as => "show_trace"
+ scope "/user/:display_name/traces/:trace_id", :module => :traces, :trace_id => /\d+/ do
get "picture" => "pictures#show", :as => "trace_picture"
get "icon" => "icons#show", :as => "trace_icon"
end
get "/traces/tag/:tag/page/:page", :page => /[1-9][0-9]*/, :to => redirect(:path => "/traces/tag/%{tag}")
get "/traces/tag/:tag" => "traces#index"
get "/traces/page/:page", :page => /[1-9][0-9]*/, :to => redirect(:path => "/traces")
- get "/traces/tag/:tag/rss" => "traces#georss", :defaults => { :format => :rss }
- get "/traces/rss" => "traces#georss", :defaults => { :format => :rss }
get "/traces/mine/tag/:tag/page/:page", :page => /[1-9][0-9]*/, :to => redirect(:path => "/traces/mine/tag/%{tag}")
get "/traces/mine/tag/:tag" => "traces#mine"
get "/traces/mine/page/:page", :page => /[1-9][0-9]*/, :to => redirect(:path => "/traces/mine")
get "/traces/mine" => "traces#mine"
get "/trace/create", :to => redirect(:path => "/traces/new")
get "/trace/:id/data" => "traces#data", :id => /\d+/, :as => "trace_data"
- get "/trace/:id/edit", :to => redirect(:path => "/traces/%{id}/edit")
+ get "/trace/:id/edit", :id => /\d+/, :to => redirect(:path => "/traces/%{id}/edit")
+
+ namespace :traces, :path => "" do
+ resource :feed, :path => "(/user/:display_name)/traces(/tag/:tag)/rss", :only => :show, :defaults => { :format => :rss }
+ end
# diary pages
resources :diary_entries, :path => "diary", :only => [:new, :create, :index] do
# user pages
get "/user/terms", :to => redirect(:path => "/account/terms")
- resources :users, :path => "user", :param => :display_name, :only => [:new, :create, :show, :destroy] do
+ resources :users, :path => "user", :param => :display_name, :only => [:new, :create, :show] do
resource :role, :controller => "user_roles", :path => "roles/:role", :only => [:create, :destroy]
scope :module => :users do
resource :issued_blocks, :path => "blocks_by", :only => :show
resource :received_blocks, :path => "blocks", :only => [:show, :edit, :destroy]
+ resource :status, :only => :update
end
end
get "/user/:display_name/account", :to => redirect(:path => "/account/edit")
- post "/user/:display_name/set_status" => "users#set_status", :as => :set_status_user
resource :account, :only => [:edit, :update, :destroy] do
scope :module => :accounts do
resource :profile, :only => [:edit, :update]
# friendships
- match "/user/:display_name/make_friend" => "friendships#make_friend", :via => [:get, :post], :as => "make_friend"
- match "/user/:display_name/remove_friend" => "friendships#remove_friend", :via => [:get, :post], :as => "remove_friend"
+ scope "/user/:display_name" do
+ resource :follow, :only => [:create, :destroy, :show], :path => "follow"
+
+ get "make_friend", :to => redirect("/user/%{display_name}/follow")
+ get "remove_friend", :to => redirect("/user/%{display_name}/follow")
+ end
# user lists
namespace :users do
default_message_query_limit: 100
# Maximum number of messages returned by inbox and outbox message api
max_message_query_limit: 100
-# Rate limit for friending
-max_friends_per_hour: 60
+# Rate limit for following
+max_follows_per_hour: 60
# Rate limit for changeset comments
min_changeset_comments_per_hour: 1
initial_changeset_comments_per_hour: 6
--- /dev/null
+class ValidateForeignKeyOnNotes < ActiveRecord::Migration[7.2]
+ def change
+ validate_foreign_key :notes, :users
+ end
+end
--
ALTER TABLE ONLY public.notes
- ADD CONSTRAINT notes_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id) NOT VALID;
+ ADD CONSTRAINT notes_user_id_fkey FOREIGN KEY (user_id) REFERENCES public.users(id);
--
('23'),
('22'),
('21'),
+('20250105154621'),
('20250104140952'),
('20241023004427'),
('20241022141247'),
assert_equal msg.body, jsm["body"]
end
+ def test_show_message_to_self_read
+ user = create(:user)
+ message = create(:message, :sender => user, :recipient => user)
+ auth_header = bearer_authorization_header user
+
+ get api_message_path(message), :headers => auth_header
+ assert_response :success
+ assert_equal "application/xml", response.media_type
+ assert_dom "message", :count => 1 do
+ assert_dom "> @message_read", "false"
+ end
+ end
+
+ def test_show_message_to_self_read_json
+ user = create(:user)
+ message = create(:message, :sender => user, :recipient => user)
+ auth_header = bearer_authorization_header user
+
+ get api_message_path(message, :format => "json"), :headers => auth_header
+ assert_response :success
+ assert_equal "application/json", response.media_type
+ js = ActiveSupport::JSON.decode(@response.body)
+ jsm = js["message"]
+ assert_not_nil jsm
+ assert jsm.key?("message_read")
+ assert_not jsm["message_read"]
+ end
+
def test_update_status
recipient = create(:user)
sender = create(:user)
maxlon = point.longitude + 0.001
maxlat = point.latitude + 0.001
bbox = "#{minlon},#{minlat},#{maxlon},#{maxlat}"
- get trackpoints_path(:bbox => bbox)
+ get api_tracepoints_path(:bbox => bbox)
assert_response :success
assert_select "gpx[version='1.0'][creator='OpenStreetMap.org']", :count => 1 do
assert_select "trk" do
maxlon = point.longitude + 0.002
maxlat = point.latitude + 0.002
bbox = "#{minlon},#{minlat},#{maxlon},#{maxlat}"
- get trackpoints_path(:bbox => bbox)
+ get api_tracepoints_path(:bbox => bbox)
assert_response :success
assert_select "gpx[version='1.0'][creator='OpenStreetMap.org']", :count => 1 do
assert_select "trk", :count => 1 do
maxlon = point.longitude + 0.002
maxlat = point.latitude + 0.002
bbox = "#{minlon},#{minlat},#{maxlon},#{maxlat}"
- get trackpoints_path(:bbox => bbox)
+ get api_tracepoints_path(:bbox => bbox)
assert_response :success
assert_select "gpx[version='1.0'][creator='OpenStreetMap.org']", :count => 1 do
assert_select "trk", :count => 1 do
end
def test_index_without_bbox
- get trackpoints_path
+ get api_tracepoints_path
assert_response :bad_request
assert_equal "The parameter bbox is required", @response.body, "A bbox param was expected"
end
def test_traces_page_less_than_zero
-10.upto(-1) do |i|
- get trackpoints_path(:page => i, :bbox => "-0.1,-0.1,0.1,0.1")
+ get api_tracepoints_path(:page => i, :bbox => "-0.1,-0.1,0.1,0.1")
assert_response :bad_request
assert_equal "Page number must be greater than or equal to 0", @response.body, "The page number was #{i}"
end
0.upto(10) do |i|
- get trackpoints_path(:page => i, :bbox => "-0.1,-0.1,0.1,0.1")
+ get api_tracepoints_path(:page => i, :bbox => "-0.1,-0.1,0.1,0.1")
assert_response :success, "The page number was #{i} and should have been accepted"
end
end
def test_bbox_too_big
@badbigbbox.each do |bbox|
- get trackpoints_path(:bbox => bbox)
+ get api_tracepoints_path(:bbox => bbox)
assert_response :bad_request, "The bbox:#{bbox} was expected to be too big"
assert_equal "The maximum bbox size is #{Settings.max_request_area}, and your request was too large. Either request a smaller area, or use planet.osm", @response.body, "bbox: #{bbox}"
end
def test_bbox_malformed
@badmalformedbbox.each do |bbox|
- get trackpoints_path(:bbox => bbox)
+ get api_tracepoints_path(:bbox => bbox)
assert_response :bad_request, "The bbox:#{bbox} was expected to be malformed"
assert_equal "The parameter bbox must be of the form min_lon,min_lat,max_lon,max_lat", @response.body, "bbox: #{bbox}"
end
def test_bbox_lon_mixedup
@badlonmixedbbox.each do |bbox|
- get trackpoints_path(:bbox => bbox)
+ get api_tracepoints_path(:bbox => bbox)
assert_response :bad_request, "The bbox:#{bbox} was expected to have the longitude mixed up"
assert_equal "The minimum longitude must be less than the maximum longitude, but it wasn't", @response.body, "bbox: #{bbox}"
end
def test_bbox_lat_mixedup
@badlatmixedbbox.each do |bbox|
- get trackpoints_path(:bbox => bbox)
+ get api_tracepoints_path(:bbox => bbox)
assert_response :bad_request, "The bbox:#{bbox} was expected to have the latitude mixed up"
assert_equal "The minimum latitude must be less than the maximum latitude, but it wasn't", @response.body, "bbox: #{bbox}"
end
def test_lat_lon_xml_format
create(:tracepoint, :latitude => (0.00004 * GeoRecord::SCALE).to_i, :longitude => (0.00008 * GeoRecord::SCALE).to_i)
- get trackpoints_path(:bbox => "0,0,0.1,0.1")
+ get api_tracepoints_path(:bbox => "0,0,0.1,0.1")
assert_match(/lat="0.0000400"/, response.body)
assert_match(/lon="0.0000800"/, response.body)
end
# Checks the display of the friends changesets listing
def test_index_friends
private_user = create(:user, :data_public => true)
- friendship = create(:friendship, :befriender => private_user)
- changeset = create(:changeset, :user => friendship.befriendee, :num_changes => 1)
+ follow = create(:follow, :follower => private_user)
+ changeset = create(:changeset, :user => follow.following, :num_changes => 1)
_changeset2 = create(:changeset, :user => create(:user), :num_changes => 1)
get friend_changesets_path
def test_index_friends
user = create(:user)
other_user = create(:user)
- friendship = create(:friendship, :befriender => user)
- diary_entry = create(:diary_entry, :user => friendship.befriendee)
+ follow = create(:follow, :follower => user)
+ diary_entry = create(:diary_entry, :user => follow.following)
_other_entry = create(:diary_entry, :user => other_user)
# Try a list of diary entries for your friends when not logged in
--- /dev/null
+require "test_helper"
+
+class FollowsControllerTest < ActionDispatch::IntegrationTest
+ ##
+ # test all routes which lead to this controller
+ def test_routes
+ assert_routing(
+ { :path => "/user/username/follow", :method => :get },
+ { :controller => "follows", :action => "show", :display_name => "username" }
+ )
+ assert_routing(
+ { :path => "/user/username/follow", :method => :post },
+ { :controller => "follows", :action => "create", :display_name => "username" }
+ )
+ assert_routing(
+ { :path => "/user/username/follow", :method => :delete },
+ { :controller => "follows", :action => "destroy", :display_name => "username" }
+ )
+ end
+
+ def test_follow
+ # Get users to work with
+ user = create(:user)
+ follow = create(:user)
+
+ # Check that the users aren't already friends
+ assert_nil Follow.find_by(:follower => user, :following => follow)
+
+ # When not logged in a GET should ask us to login
+ get follow_path(follow)
+ assert_redirected_to login_path(:referer => follow_path(follow))
+
+ # When not logged in a POST should error
+ post follow_path(follow)
+ assert_response :forbidden
+ assert_nil Follow.find_by(:follower => user, :following => follow)
+
+ session_for(user)
+
+ # When logged in a GET should get a confirmation page
+ get follow_path(follow)
+ assert_response :success
+ assert_template :show
+ assert_select "a[href*='test']", 0
+ assert_nil Follow.find_by(:follower => user, :following => follow)
+
+ # When logged in a POST should add the follow
+ assert_difference "ActionMailer::Base.deliveries.size", 1 do
+ perform_enqueued_jobs do
+ post follow_path(follow)
+ end
+ end
+ assert_redirected_to user_path(follow)
+ assert_match(/You are now following/, flash[:notice])
+ assert Follow.find_by(:follower => user, :following => follow)
+ email = ActionMailer::Base.deliveries.first
+ assert_equal 1, email.to.count
+ assert_equal follow.email, email.to.first
+ ActionMailer::Base.deliveries.clear
+
+ # A second POST should report that the follow already exists
+ assert_no_difference "ActionMailer::Base.deliveries.size" do
+ perform_enqueued_jobs do
+ post follow_path(follow)
+ end
+ end
+ assert_redirected_to user_path(follow)
+ assert_match(/You already follow/, flash[:warning])
+ assert Follow.find_by(:follower => user, :following => follow)
+ end
+
+ def test_follow_with_referer
+ # Get users to work with
+ user = create(:user)
+ follow = create(:user)
+ session_for(user)
+
+ # Check that the users aren't already friends
+ assert_nil Follow.find_by(:follower => user, :following => follow)
+
+ # The GET should preserve any referer
+ get follow_path(follow), :params => { :referer => "/test" }
+ assert_response :success
+ assert_template :show
+ assert_select "a[href*='test']"
+ assert_nil Follow.find_by(:follower => user, :following => follow)
+
+ # When logged in a POST should add the follow and refer us
+ assert_difference "ActionMailer::Base.deliveries.size", 1 do
+ perform_enqueued_jobs do
+ post follow_path(follow), :params => { :referer => "/test" }
+ end
+ end
+ assert_redirected_to "/test"
+ assert_match(/You are now following/, flash[:notice])
+ assert Follow.find_by(:follower => user, :following => follow)
+ email = ActionMailer::Base.deliveries.first
+ assert_equal 1, email.to.count
+ assert_equal follow.email, email.to.first
+ ActionMailer::Base.deliveries.clear
+ end
+
+ def test_follow_unknown_user
+ # Should error when a bogus user is specified
+ session_for(create(:user))
+ get follow_path("No Such User")
+ assert_response :not_found
+ assert_template :no_such_user
+ end
+
+ def test_unfollow
+ # Get users to work with
+ user = create(:user)
+ follow = create(:user)
+ create(:follow, :follower => user, :following => follow)
+
+ # Check that the users are friends
+ assert Follow.find_by(:follower => user, :following => follow)
+
+ # When not logged in a GET should ask us to login
+ get follow_path(follow)
+ assert_redirected_to login_path(:referer => follow_path(follow))
+
+ # When not logged in a POST should error
+ delete follow_path, :params => { :display_name => follow.display_name }
+ assert_response :forbidden
+ assert Follow.find_by(:follower => user, :following => follow)
+
+ session_for(user)
+
+ # When logged in a GET should get a confirmation page
+ get follow_path(follow)
+ assert_response :success
+ assert_template :show
+ assert_select "a[href*='test']", 0
+ assert Follow.find_by(:follower => user, :following => follow)
+
+ # When logged in a DELETE should remove the follow
+ delete follow_path(follow)
+ assert_redirected_to user_path(follow)
+ assert_match(/You successfully unfollowed/, flash[:notice])
+ assert_nil Follow.find_by(:follower => user, :following => follow)
+
+ # A second DELETE should report that the follow does not exist
+ delete follow_path(follow)
+ assert_redirected_to user_path(follow)
+ assert_match(/You are not following/, flash[:error])
+ assert_nil Follow.find_by(:follower => user, :following => follow)
+ end
+
+ def test_unfollow_with_referer
+ # Get users to work with
+ user = create(:user)
+ follow = create(:user)
+ create(:follow, :follower => user, :following => follow)
+ session_for(user)
+
+ # Check that the users are friends
+ assert Follow.find_by(:follower => user, :following => follow)
+
+ # The GET should preserve any referer
+ get follow_path(follow), :params => { :referer => "/test" }
+ assert_response :success
+ assert_template :show
+ assert_select "a[href*='test']"
+ assert Follow.find_by(:follower => user, :following => follow)
+
+ # When logged in a POST should remove the follow and refer
+ delete follow_path(follow), :params => { :referer => "/test" }
+ assert_redirected_to "/test"
+ assert_match(/You successfully unfollowed/, flash[:notice])
+ assert_nil Follow.find_by(:follower => user, :following => follow)
+ end
+
+ def test_unfollow_unknown_user
+ # Should error when a bogus user is specified
+ session_for(create(:user))
+ get follow_path("No Such User")
+ assert_response :not_found
+ assert_template :no_such_user
+ end
+end
+++ /dev/null
-require "test_helper"
-
-class FriendshipsControllerTest < ActionDispatch::IntegrationTest
- ##
- # test all routes which lead to this controller
- def test_routes
- assert_routing(
- { :path => "/user/username/make_friend", :method => :get },
- { :controller => "friendships", :action => "make_friend", :display_name => "username" }
- )
- assert_routing(
- { :path => "/user/username/make_friend", :method => :post },
- { :controller => "friendships", :action => "make_friend", :display_name => "username" }
- )
- assert_routing(
- { :path => "/user/username/remove_friend", :method => :get },
- { :controller => "friendships", :action => "remove_friend", :display_name => "username" }
- )
- assert_routing(
- { :path => "/user/username/remove_friend", :method => :post },
- { :controller => "friendships", :action => "remove_friend", :display_name => "username" }
- )
- end
-
- def test_make_friend
- # Get users to work with
- user = create(:user)
- friend = create(:user)
-
- # Check that the users aren't already friends
- assert_nil Friendship.find_by(:befriender => user, :befriendee => friend)
-
- # When not logged in a GET should ask us to login
- get make_friend_path(friend)
- assert_redirected_to login_path(:referer => make_friend_path(friend))
-
- # When not logged in a POST should error
- post make_friend_path(friend)
- assert_response :forbidden
- assert_nil Friendship.find_by(:befriender => user, :befriendee => friend)
-
- session_for(user)
-
- # When logged in a GET should get a confirmation page
- get make_friend_path(friend)
- assert_response :success
- assert_template :make_friend
- assert_select "form" do
- assert_select "input[type='hidden'][name='referer']", 0
- assert_select "input[type='submit']", 1
- end
- assert_nil Friendship.find_by(:befriender => user, :befriendee => friend)
-
- # When logged in a POST should add the friendship
- assert_difference "ActionMailer::Base.deliveries.size", 1 do
- perform_enqueued_jobs do
- post make_friend_path(friend)
- end
- end
- assert_redirected_to user_path(friend)
- assert_match(/is now your friend/, flash[:notice])
- assert Friendship.find_by(:befriender => user, :befriendee => friend)
- email = ActionMailer::Base.deliveries.first
- assert_equal 1, email.to.count
- assert_equal friend.email, email.to.first
- ActionMailer::Base.deliveries.clear
-
- # A second POST should report that the friendship already exists
- assert_no_difference "ActionMailer::Base.deliveries.size" do
- perform_enqueued_jobs do
- post make_friend_path(friend)
- end
- end
- assert_redirected_to user_path(friend)
- assert_match(/You are already friends with/, flash[:warning])
- assert Friendship.find_by(:befriender => user, :befriendee => friend)
- end
-
- def test_make_friend_with_referer
- # Get users to work with
- user = create(:user)
- friend = create(:user)
- session_for(user)
-
- # Check that the users aren't already friends
- assert_nil Friendship.find_by(:befriender => user, :befriendee => friend)
-
- # The GET should preserve any referer
- get make_friend_path(friend), :params => { :referer => "/test" }
- assert_response :success
- assert_template :make_friend
- assert_select "form" do
- assert_select "input[type='hidden'][name='referer'][value='/test']", 1
- assert_select "input[type='submit']", 1
- end
- assert_nil Friendship.find_by(:befriender => user, :befriendee => friend)
-
- # When logged in a POST should add the friendship and refer us
- assert_difference "ActionMailer::Base.deliveries.size", 1 do
- perform_enqueued_jobs do
- post make_friend_path(friend), :params => { :referer => "/test" }
- end
- end
- assert_redirected_to "/test"
- assert_match(/is now your friend/, flash[:notice])
- assert Friendship.find_by(:befriender => user, :befriendee => friend)
- email = ActionMailer::Base.deliveries.first
- assert_equal 1, email.to.count
- assert_equal friend.email, email.to.first
- ActionMailer::Base.deliveries.clear
- end
-
- def test_make_friend_unknown_user
- # Should error when a bogus user is specified
- session_for(create(:user))
- get make_friend_path("No Such User")
- assert_response :not_found
- assert_template :no_such_user
- end
-
- def test_remove_friend
- # Get users to work with
- user = create(:user)
- friend = create(:user)
- create(:friendship, :befriender => user, :befriendee => friend)
-
- # Check that the users are friends
- assert Friendship.find_by(:befriender => user, :befriendee => friend)
-
- # When not logged in a GET should ask us to login
- get remove_friend_path(friend)
- assert_redirected_to login_path(:referer => remove_friend_path(friend))
-
- # When not logged in a POST should error
- post remove_friend_path, :params => { :display_name => friend.display_name }
- assert_response :forbidden
- assert Friendship.find_by(:befriender => user, :befriendee => friend)
-
- session_for(user)
-
- # When logged in a GET should get a confirmation page
- get remove_friend_path(friend)
- assert_response :success
- assert_template :remove_friend
- assert_select "form" do
- assert_select "input[type='hidden'][name='referer']", 0
- assert_select "input[type='submit']", 1
- end
- assert Friendship.find_by(:befriender => user, :befriendee => friend)
-
- # When logged in a POST should remove the friendship
- post remove_friend_path(friend)
- assert_redirected_to user_path(friend)
- assert_match(/was removed from your friends/, flash[:notice])
- assert_nil Friendship.find_by(:befriender => user, :befriendee => friend)
-
- # A second POST should report that the friendship does not exist
- post remove_friend_path(friend)
- assert_redirected_to user_path(friend)
- assert_match(/is not one of your friends/, flash[:error])
- assert_nil Friendship.find_by(:befriender => user, :befriendee => friend)
- end
-
- def test_remove_friend_with_referer
- # Get users to work with
- user = create(:user)
- friend = create(:user)
- create(:friendship, :befriender => user, :befriendee => friend)
- session_for(user)
-
- # Check that the users are friends
- assert Friendship.find_by(:befriender => user, :befriendee => friend)
-
- # The GET should preserve any referer
- get remove_friend_path(friend), :params => { :referer => "/test" }
- assert_response :success
- assert_template :remove_friend
- assert_select "form" do
- assert_select "input[type='hidden'][name='referer'][value='/test']", 1
- assert_select "input[type='submit']", 1
- end
- assert Friendship.find_by(:befriender => user, :befriendee => friend)
-
- # When logged in a POST should remove the friendship and refer
- post remove_friend_path(friend), :params => { :referer => "/test" }
- assert_redirected_to "/test"
- assert_match(/was removed from your friends/, flash[:notice])
- assert_nil Friendship.find_by(:befriender => user, :befriendee => friend)
- end
-
- def test_remove_friend_unknown_user
- # Should error when a bogus user is specified
- session_for(create(:user))
- get remove_friend_path("No Such User")
- assert_response :not_found
- assert_template :no_such_user
- end
-end
assert_select "li", :count => 3
assert_select "li", :text => "Read user preferences"
assert_select "li", :text => "Modify user preferences"
- assert_select "li", :text => "Create diary entries, comments and make friends"
+ assert_select "li", :text => "Create diary entries and comments"
end
end
--- /dev/null
+require "test_helper"
+
+module Traces
+ class FeedsControllerTest < ActionDispatch::IntegrationTest
+ ##
+ # test all routes which lead to this controller
+ def test_routes
+ assert_routing(
+ { :path => "/traces/rss", :method => :get },
+ { :controller => "traces/feeds", :action => "show", :format => :rss }
+ )
+ assert_routing(
+ { :path => "/traces/tag/tagname/rss", :method => :get },
+ { :controller => "traces/feeds", :action => "show", :tag => "tagname", :format => :rss }
+ )
+ assert_routing(
+ { :path => "/user/username/traces/rss", :method => :get },
+ { :controller => "traces/feeds", :action => "show", :display_name => "username", :format => :rss }
+ )
+ assert_routing(
+ { :path => "/user/username/traces/tag/tagname/rss", :method => :get },
+ { :controller => "traces/feeds", :action => "show", :display_name => "username", :tag => "tagname", :format => :rss }
+ )
+ end
+
+ def test_show
+ user = create(:user)
+ # The fourth test below is surprisingly sensitive to timestamp ordering when the timestamps are equal.
+ trace_a = create(:trace, :visibility => "public", :timestamp => 4.seconds.ago) do |trace|
+ create(:tracetag, :trace => trace, :tag => "London")
+ end
+ trace_b = create(:trace, :visibility => "public", :timestamp => 3.seconds.ago) do |trace|
+ create(:tracetag, :trace => trace, :tag => "Birmingham")
+ end
+ create(:trace, :visibility => "private", :user => user, :timestamp => 2.seconds.ago) do |trace|
+ create(:tracetag, :trace => trace, :tag => "London")
+ end
+ create(:trace, :visibility => "private", :user => user, :timestamp => 1.second.ago) do |trace|
+ create(:tracetag, :trace => trace, :tag => "Birmingham")
+ end
+
+ # First with the public feed
+ get traces_feed_path
+ check_trace_feed [trace_b, trace_a]
+
+ # Restrict traces to those with a given tag
+ get traces_feed_path(:tag => "London")
+ check_trace_feed [trace_a]
+ end
+
+ def test_show_user
+ user = create(:user)
+ second_user = create(:user)
+ create(:user)
+ create(:trace)
+ trace_b = create(:trace, :visibility => "public", :timestamp => 4.seconds.ago, :user => user)
+ trace_c = create(:trace, :visibility => "public", :timestamp => 3.seconds.ago, :user => user) do |trace|
+ create(:tracetag, :trace => trace, :tag => "London")
+ end
+ create(:trace, :visibility => "private")
+
+ # Test a user with no traces
+ get traces_feed_path(:display_name => second_user)
+ check_trace_feed []
+
+ # Test the user with the traces - should see only public ones
+ get traces_feed_path(:display_name => user)
+ check_trace_feed [trace_c, trace_b]
+
+ # Should only see traces with the correct tag when a tag is specified
+ get traces_feed_path(:display_name => user, :tag => "London")
+ check_trace_feed [trace_c]
+
+ # Should no traces if the user does not exist
+ get traces_feed_path(:display_name => "UnknownUser")
+ check_trace_feed []
+ end
+
+ private
+
+ def check_trace_feed(traces)
+ assert_response :success
+ assert_template "traces/feeds/show"
+ assert_equal "application/rss+xml", @response.media_type
+ assert_select "rss", :count => 1 do
+ assert_select "channel", :count => 1 do
+ assert_select "title"
+ assert_select "description"
+ assert_select "link"
+ assert_select "image"
+ assert_select "item", :count => traces.length do |items|
+ traces.zip(items).each do |trace, item|
+ assert_select item, "title", trace.name
+ assert_select item, "link", "http://www.example.com/user/#{ERB::Util.u(trace.user.display_name)}/traces/#{trace.id}"
+ assert_select item, "guid", "http://www.example.com/user/#{ERB::Util.u(trace.user.display_name)}/traces/#{trace.id}"
+ assert_select item, "description" do
+ assert_dom_encoded do
+ assert_select "img[src='#{trace_icon_url trace.user, trace}']"
+ end
+ end
+ # assert_select item, "dc:creator", trace.user.display_name
+ assert_select item, "pubDate", trace.timestamp.rfc822
+ end
+ end
+ end
+ end
+ end
+ end
+end
{ :controller => "traces", :action => "mine", :tag => "tagname" }
)
- assert_routing(
- { :path => "/traces/rss", :method => :get },
- { :controller => "traces", :action => "georss", :format => :rss }
- )
- assert_routing(
- { :path => "/traces/tag/tagname/rss", :method => :get },
- { :controller => "traces", :action => "georss", :tag => "tagname", :format => :rss }
- )
- assert_routing(
- { :path => "/user/username/traces/rss", :method => :get },
- { :controller => "traces", :action => "georss", :display_name => "username", :format => :rss }
- )
- assert_routing(
- { :path => "/user/username/traces/tag/tagname/rss", :method => :get },
- { :controller => "traces", :action => "georss", :display_name => "username", :tag => "tagname", :format => :rss }
- )
-
assert_routing(
{ :path => "/user/username/traces/1", :method => :get },
{ :controller => "traces", :action => "show", :display_name => "username", :id => "1" }
end
end
- # Check the RSS feed
- def test_rss
- user = create(:user)
- # The fourth test below is surprisingly sensitive to timestamp ordering when the timestamps are equal.
- trace_a = create(:trace, :visibility => "public", :timestamp => 4.seconds.ago) do |trace|
- create(:tracetag, :trace => trace, :tag => "London")
- end
- trace_b = create(:trace, :visibility => "public", :timestamp => 3.seconds.ago) do |trace|
- create(:tracetag, :trace => trace, :tag => "Birmingham")
- end
- create(:trace, :visibility => "private", :user => user, :timestamp => 2.seconds.ago) do |trace|
- create(:tracetag, :trace => trace, :tag => "London")
- end
- create(:trace, :visibility => "private", :user => user, :timestamp => 1.second.ago) do |trace|
- create(:tracetag, :trace => trace, :tag => "Birmingham")
- end
-
- # First with the public feed
- get traces_rss_path
- check_trace_feed [trace_b, trace_a]
-
- # Restrict traces to those with a given tag
- get traces_rss_path(:tag => "London")
- check_trace_feed [trace_a]
- end
-
- # Check the RSS feed for a specific user
- def test_rss_user
- user = create(:user)
- second_user = create(:user)
- create(:user)
- create(:trace)
- trace_b = create(:trace, :visibility => "public", :timestamp => 4.seconds.ago, :user => user)
- trace_c = create(:trace, :visibility => "public", :timestamp => 3.seconds.ago, :user => user) do |trace|
- create(:tracetag, :trace => trace, :tag => "London")
- end
- create(:trace, :visibility => "private")
-
- # Test a user with no traces
- get traces_rss_path(:display_name => second_user.display_name)
- check_trace_feed []
-
- # Test the user with the traces - should see only public ones
- get traces_rss_path(:display_name => user.display_name)
- check_trace_feed [trace_c, trace_b]
-
- # Should only see traces with the correct tag when a tag is specified
- get traces_rss_path(:display_name => user.display_name, :tag => "London")
- check_trace_feed [trace_c]
-
- # Should no traces if the user does not exist
- get traces_rss_path(:display_name => "UnknownUser")
- check_trace_feed []
- end
-
# Test showing a trace
def test_show
public_trace_file = create(:trace, :visibility => "public")
private
- def check_trace_feed(traces)
- assert_response :success
- assert_template "georss"
- assert_equal "application/rss+xml", @response.media_type
- assert_select "rss", :count => 1 do
- assert_select "channel", :count => 1 do
- assert_select "title"
- assert_select "description"
- assert_select "link"
- assert_select "image"
- assert_select "item", :count => traces.length do |items|
- traces.zip(items).each do |trace, item|
- assert_select item, "title", trace.name
- assert_select item, "link", "http://www.example.com/user/#{ERB::Util.u(trace.user.display_name)}/traces/#{trace.id}"
- assert_select item, "guid", "http://www.example.com/user/#{ERB::Util.u(trace.user.display_name)}/traces/#{trace.id}"
- assert_select item, "description" do
- assert_dom_encoded do
- assert_select "img[src='#{trace_icon_url trace.user, trace}']"
- end
- end
- # assert_select item, "dc:creator", trace.user.display_name
- assert_select item, "pubDate", trace.timestamp.rfc822
- end
- end
- end
- end
- end
-
def check_trace_index(traces)
assert_response :success
assert_template "index"
--- /dev/null
+require "test_helper"
+
+module Users
+ class StatusesControllerTest < ActionDispatch::IntegrationTest
+ ##
+ # test all routes which lead to this controller
+ def test_routes
+ assert_routing(
+ { :path => "/user/username/status", :method => :put },
+ { :controller => "users/statuses", :action => "update", :user_display_name => "username" }
+ )
+ end
+
+ def test_update
+ user = create(:user)
+
+ # Try without logging in
+ put user_status_path(user, :event => "confirm")
+ assert_response :forbidden
+
+ # Now try as a normal user
+ session_for(user)
+ put user_status_path(user, :event => "confirm")
+ assert_redirected_to :controller => "/errors", :action => :forbidden
+
+ # Finally try as an administrator
+ session_for(create(:administrator_user))
+ put user_status_path(user, :event => "confirm")
+ assert_redirected_to user_path(user)
+ assert_equal "confirmed", User.find(user.id).status
+ end
+
+ def test_destroy
+ user = create(:user, :home_lat => 12.1, :home_lon => 12.1, :description => "test")
+
+ # Try without logging in
+ put user_status_path(user, :event => "soft_destroy")
+ assert_response :forbidden
+
+ # Now try as a normal user
+ session_for(user)
+ put user_status_path(user, :event => "soft_destroy")
+ assert_redirected_to :controller => "/errors", :action => :forbidden
+
+ # Finally try as an administrator
+ session_for(create(:administrator_user))
+ put user_status_path(user, :event => "soft_destroy")
+ assert_redirected_to user_path(user)
+
+ # Check that the user was deleted properly
+ user.reload
+ assert_equal "user_#{user.id}", user.display_name
+ assert_equal "", user.description
+ assert_nil user.home_lat
+ assert_nil user.home_lon
+ assert_not user.avatar.attached?
+ assert_not user.email_valid
+ assert_nil user.new_email
+ assert_nil user.auth_provider
+ assert_nil user.auth_uid
+ assert_equal "deleted", user.status
+ end
+ end
+end
{ :path => "/user/username", :method => :get },
{ :controller => "users", :action => "show", :display_name => "username" }
)
-
- assert_routing(
- { :path => "/user/username/set_status", :method => :post },
- { :controller => "users", :action => "set_status", :display_name => "username" }
- )
- assert_routing(
- { :path => "/user/username", :method => :delete },
- { :controller => "users", :action => "destroy", :display_name => "username" }
- )
end
# The user creation page loads
end
end
- def test_set_status
- user = create(:user)
-
- # Try without logging in
- post set_status_user_path(user), :params => { :event => "confirm" }
- assert_response :forbidden
-
- # Now try as a normal user
- session_for(user)
- post set_status_user_path(user), :params => { :event => "confirm" }
- assert_redirected_to :controller => :errors, :action => :forbidden
-
- # Finally try as an administrator
- session_for(create(:administrator_user))
- post set_status_user_path(user), :params => { :event => "confirm" }
- assert_redirected_to :action => :show, :display_name => user.display_name
- assert_equal "confirmed", User.find(user.id).status
- end
-
- def test_destroy
- user = create(:user, :home_lat => 12.1, :home_lon => 12.1, :description => "test")
-
- # Try without logging in
- delete user_path(user)
- assert_response :forbidden
-
- # Now try as a normal user
- session_for(user)
- delete user_path(user)
- assert_redirected_to :controller => :errors, :action => :forbidden
-
- # Finally try as an administrator
- session_for(create(:administrator_user))
- delete user_path(user)
- assert_redirected_to :action => :show, :display_name => user.display_name
-
- # Check that the user was deleted properly
- user.reload
- assert_equal "user_#{user.id}", user.display_name
- assert_equal "", user.description
- assert_nil user.home_lat
- assert_nil user.home_lon
- assert_not user.avatar.attached?
- assert_not user.email_valid
- assert_nil user.new_email
- assert_nil user.auth_provider
- assert_nil user.auth_uid
- assert_equal "deleted", user.status
- end
-
def test_auth_failure_callback
get auth_failure_path
assert_redirected_to login_path
--- /dev/null
+FactoryBot.define do
+ factory :follow do
+ follower :factory => :user
+ following :factory => :user
+ end
+end
+++ /dev/null
-FactoryBot.define do
- factory :friendship do
- befriender :factory => :user
- befriendee :factory => :user
- end
-end
assert_predicate user, :valid?, "user_0 display_name is invalid but it hasn't been changed"
end
- def test_friends_with
+ def test_follows
alice = create(:user, :active)
bob = create(:user, :active)
charlie = create(:user, :active)
- create(:friendship, :befriender => alice, :befriendee => bob)
-
- assert alice.friends_with?(bob)
- assert_not alice.friends_with?(charlie)
- assert_not bob.friends_with?(alice)
- assert_not bob.friends_with?(charlie)
- assert_not charlie.friends_with?(bob)
- assert_not charlie.friends_with?(alice)
+ create(:follow, :follower => alice, :following => bob)
+
+ assert alice.follows?(bob)
+ assert_not alice.follows?(charlie)
+ assert_not bob.follows?(alice)
+ assert_not bob.follows?(charlie)
+ assert_not charlie.follows?(bob)
+ assert_not charlie.follows?(alice)
end
def test_users_nearby
def test_friends
norm = create(:user, :active)
sec = create(:user, :active)
- create(:friendship, :befriender => norm, :befriendee => sec)
+ create(:follow, :follower => norm, :following => sec)
- assert_equal [sec], norm.friends
- assert_equal 1, norm.friends.size
+ assert_equal [sec], norm.followings
+ assert_equal 1, norm.followings.size
- assert_empty sec.friends
- assert_equal 0, sec.friends.size
+ assert_empty sec.followings
+ assert_equal 0, sec.followings.size
end
def test_user_preferred_editor
require "application_system_test_case"
class DashboardSystemTest < ApplicationSystemTestCase
- test "show no users if have no friends" do
+ test "show no users if have no followings" do
user = create(:user)
sign_in_as(user)
visit dashboard_path
- assert_text "You have not added any friends yet."
+ assert_text "You have not followed any user yet."
end
test "show users if have friends" do
user = create(:user, :home_lon => 1.1, :home_lat => 1.1)
friend_user = create(:user, :home_lon => 1.2, :home_lat => 1.2)
- create(:friendship, :befriender => user, :befriendee => friend_user)
+ create(:follow, :follower => user, :following => friend_user)
create(:changeset, :user => friend_user)
sign_in_as(user)
visit dashboard_path
- assert_no_text "You have not added any friends yet."
+ assert_no_text "You have not followed any user yet."
- friends_heading = find :element, "h2", :text => "My friends"
+ friends_heading = find :element, "h2", :text => "Followings"
others_heading = find :element, "h2", :text => "Other nearby users"
assert_link friend_user.display_name, :below => friends_heading, :above => others_heading
end
+
+ test "show nearby users with ability to follow" do
+ user = create(:user, :home_lon => 1.1, :home_lat => 1.1)
+ nearby_user = create(:user, :home_lon => 1.2, :home_lat => 1.2)
+ sign_in_as(user)
+
+ visit dashboard_path
+
+ within_content_body do
+ others_nearby_heading = find :element, "h2", :text => "Other nearby users"
+
+ assert_no_text "There are no other users who admit to mapping nearby yet"
+ assert_link nearby_user.display_name, :below => others_nearby_heading
+ assert_link "Follow", :below => others_nearby_heading
+
+ click_on "Follow"
+
+ followings_heading = find :element, "h2", :text => "Followings"
+ others_nearby_heading = find :element, "h2", :text => "Other nearby users"
+
+ assert_text "There are no other users who admit to mapping nearby yet"
+ assert_link nearby_user.display_name, :below => followings_heading, :above => others_nearby_heading
+ assert_link "Unfollow", :below => followings_heading, :above => others_nearby_heading
+ end
+ end
end
--- /dev/null
+require "application_system_test_case"
+
+class FollowsTest < ApplicationSystemTestCase
+ test "show message when max frienships limit is exceeded" do
+ following = create(:user)
+
+ sign_in_as create(:user)
+
+ with_settings(:max_follows_per_hour => 0) do
+ visit user_path(following)
+ assert_link "Follow"
+
+ click_on "Follow"
+ assert_text "You have followed a lot of users recently"
+ assert_link "Follow"
+ end
+ end
+end
+++ /dev/null
-require "application_system_test_case"
-
-class FriendshipsTest < ApplicationSystemTestCase
- test "show message when max frienships limit is exceeded" do
- befriendee = create(:user)
-
- sign_in_as create(:user)
-
- with_settings(:max_friends_per_hour => 0) do
- visit user_path(befriendee)
- assert_link "Add Friend"
-
- click_on "Add Friend"
- assert_text "You have friended a lot of users recently"
- assert_link "Add Friend"
- end
- end
-end