ruby-version: 3.1
rubygems: 3.4.10
bundler-cache: true
+ - name: Create base branch
+ run: |
+ git fetch ${{ github.event.pull_request.base.repo.clone_url }} ${{ github.event.pull_request.base.ref }}:danger_base
+ - name: Create head branch
+ run: |
+ git fetch ${{ github.event.pull_request.head.repo.clone_url }} ${{ github.event.pull_request.head.ref }}:danger_head
- name: Danger
env:
DANGER_GITHUB_BEARER_TOKEN: ${{ secrets.GITHUB_TOKEN }}
* https://www.ruby-lang.org/ - The homepage of Ruby which has more links and some great tutorials.
* https://rubyonrails.org/ - The homepage of Rails, also has links and tutorials.
+## Assigning Issues
+
+We don't assign issues to individual contributors. You are welcome to work on any
+issue, and there's no need to ask first.
+
+For more details see [our FAQ](FAQ.md)]
+
## Coding style
We use [Rubocop](https://github.com/rubocop-hq/rubocop) (for ruby files)
See [PR #1296](https://github.com/openstreetmap/openstreetmap-website/pull/1296)
as an example.
+
+## Why don't you assign issues?
+
+We don't assign issues to volunteers for several reasons. The main reasons are that it discourages other volunteers from working on the issue, and the process turns into an unproductive administrative overhead for our team.
+
+There's no need to ask for an issue to be assigned before anyone starts working on it. Everyone is welcome to work on any issue at any time.
+
+In our experience, most people who ask for an issue to be assigned to them never create a pull request. So we would need to keep track of the assigned issues, and remember to unassign them a week or two into the future, when it is likely that they will not be making a PR. Assigned developers might feel bad if they perceive that we're unhappy with their progress, further discouraging them from contributing. Or we will get drawn into discussions about needing more time, or re-assigning them again, or so on. So it is best not to assign in the first place.
+
+The risk that two people are both genuinely working on the same task in the same hour or two is vanishingly remote, and doesn't outweigh the downsides described above. A better approach is to encourage people to simply work on the task and create a pull request, at which point everyone knows that they are actually working on the issue and not just planning/hoping/wishing to do so.
group :development do
gem "better_errors"
gem "binding_of_caller"
- gem "danger", :github => "tomhughes/danger", :ref => "pull-request-target"
+ gem "danger"
gem "danger-auto_label"
gem "debug_inspector"
gem "i18n-tasks"
-GIT
- remote: https://github.com/tomhughes/danger.git
- revision: a265cf74d2f464a25796b48d95697f5eed553454
- ref: pull-request-target
- specs:
- danger (9.5.1)
- base64 (~> 0.2)
- claide (~> 1.0)
- claide-plugins (>= 0.9.2)
- colored2 (~> 3.1)
- cork (~> 0.1)
- faraday (>= 0.9.0, < 3.0)
- faraday-http-cache (~> 2.0)
- git (~> 1.13)
- kramdown (~> 2.3)
- kramdown-parser-gfm (~> 1.0)
- octokit (>= 4.0)
- pstore (~> 0.1)
- terminal-table (>= 1, < 4)
-
GEM
remote: https://rubygems.org/
specs:
rexml
crass (1.0.6)
dalli (3.2.8)
+ danger (9.5.1)
+ base64 (~> 0.2)
+ claide (~> 1.0)
+ claide-plugins (>= 0.9.2)
+ colored2 (~> 3.1)
+ cork (~> 0.1)
+ faraday (>= 0.9.0, < 3.0)
+ faraday-http-cache (~> 2.0)
+ git (~> 1.13)
+ kramdown (~> 2.3)
+ kramdown-parser-gfm (~> 1.0)
+ octokit (>= 4.0)
+ pstore (~> 0.1)
+ terminal-table (>= 1, < 4)
danger-auto_label (1.3.1)
danger-plugin-api (~> 1.0)
danger-plugin-api (1.0.0)
config
connection_pool
dalli
- danger!
+ danger
danger-auto_label
dartsass-sprockets
debug
# vi: set ft=ruby :
Vagrant.configure("2") do |config|
- # use official ubuntu image for virtualbox
+ # use official debian image
+ config.vm.box = "debian/bookworm64"
+
+ # configure virtualbox provider
config.vm.provider "virtualbox" do |vb, override|
- override.vm.box = "ubuntu/noble64"
override.vm.synced_folder ".", "/srv/openstreetmap-website"
vb.customize ["modifyvm", :id, "--memory", "4096"]
vb.customize ["modifyvm", :id, "--cpus", "2"]
# Use sshfs sharing if available, otherwise NFS sharing
sharing_type = Vagrant.has_plugin?("vagrant-sshfs") ? "sshfs" : "nfs"
- # use third party image and sshfs or NFS sharing for lxc
+ # configure lxc provider
config.vm.provider "lxc" do |_, override|
- override.vm.box = "generic/ubuntu2404"
override.vm.synced_folder ".", "/srv/openstreetmap-website", :type => sharing_type
end
- # use third party image and sshfs or NFS sharing for libvirt
- config.vm.provider "libvirt" do |_, override|
- override.vm.box = "generic/ubuntu2404"
+ # configure libvirt provider
+ config.vm.provider "libvirt" do |libvirt, override|
override.vm.synced_folder ".", "/srv/openstreetmap-website", :type => sharing_type
+ libvirt.memory = 4096
+ libvirt.cpus = 2
end
# configure shared package cache if possible
//= require qs/dist/qs
$(document).ready(function () {
- var loaderTimeout;
-
var map = new L.OSM.Map("map", {
zoomControl: false,
layerControl: false,
map.setSidebarOverlaid(false);
- clearTimeout(loaderTimeout);
-
- loaderTimeout = setTimeout(function () {
- $("#sidebar_loader").show();
- }, 200);
+ $("#sidebar_loader").show().addClass("delayed-fade-in");
// IE<10 doesn't respect Vary: X-Requested-With header, so
// prevent caching the XHR response as a full-page URL.
url: content_path,
dataType: "html",
complete: function (xhr) {
- clearTimeout(loaderTimeout);
$("#flash").empty();
- $("#sidebar_loader").hide();
+ $("#sidebar_loader").removeClass("delayed-fade-in").hide();
var content = $(xhr.responseText);
newNote.on("remove", function () {
addNoteButton.removeClass("active");
- }).on("dragstart", function () {
- $(newNote).stopTime("removenote");
}).on("dragend", function () {
content.find("textarea").focus();
});
var container = $(this).closest(".richtext_container");
var preview = container.find(".tab-pane[id$='_preview']");
- preview.children(".richtext_placeholder").attr("hidden", true);
+ preview.children(".richtext_placeholder").attr("hidden", true).removeClass("delayed-fade-in");
preview.children(".richtext").empty();
});
var preview = container.find(".tab-pane[id$='_preview']");
if (preview.children(".richtext").contents().length === 0) {
- preview.oneTime(200, "loading", function () {
- preview.children(".richtext_placeholder").removeAttr("hidden");
- });
+ preview.children(".richtext_placeholder").removeAttr("hidden").addClass("delayed-fade-in");
preview.children(".richtext").load(editor.data("previewUrl"), { text: editor.val() }, function () {
- preview.stopTime("loading");
- preview.children(".richtext_placeholder").attr("hidden", true);
+ preview.children(".richtext_placeholder").attr("hidden", true).removeClass("delayed-fade-in");
});
}
});
}
}
+/* Utility for delayed loading spinner */
+
+.delayed-fade-in {
+ animation: 300ms linear forwards delayed-fade-in;
+}
+
+@keyframes delayed-fade-in {
+ 0% { opacity: 0 }
+ 66% { opacity: 0 }
+ 100% { opacity: 1 }
+}
+
/* Rules for the header */
#menu-icon {
end
def create
- session[:remember_me] ||= params[:remember_me]
+ session[:remember_me] = params[:remember_me] == "yes"
referer = safe_referer(params[:referer]) if params[:referer]
end
def show
- if current_user && current_user == @user_block.user
+ if current_user && current_user == @user_block.user && !@user_block.deactivates_at
@user_block.needs_view = false
@user_block.deactivates_at = [@user_block.ends_at, Time.now.utc].max
@user_block.save!
<%= f.password_field :password, :autocomplete => "on", :tabindex => 2, :value => "", :skip_label => true %>
<%= f.form_group do %>
- <%= f.check_box :remember_me, { :label => t(".remember"), :tabindex => 3, :checked => (params[:remember_me] == "yes") }, "yes" %>
+ <%= f.check_box :remember_me, { :label => t(".remember"), :tabindex => 3, :checked => (params[:remember_me] == "true") }, "yes" %>
<% end %>
<div class="mb-3">
# abort on error
set -e
-# set locale to UTF-8 compatible. apologies to non-english speakers...
-locale-gen en_GB.utf8
-update-locale LANG=en_GB.utf8 LC_ALL=en_GB.utf8
-export LANG=en_GB.utf8
-export LC_ALL=en_GB.utf8
-
# make sure we have up-to-date packages
apt-get update
# install packages as explained in INSTALL.md
apt-get install -y ruby ruby-dev ruby-bundler \
libxml2-dev libxslt1-dev nodejs npm \
- build-essential git-core \
+ build-essential git-core firefox-esr \
postgresql postgresql-contrib libpq-dev libvips-dev libyaml-dev \
libsasl2-dev libffi-dev libgd-dev libarchive-dev libbz2-dev
npm install --global yarn
assert_redirected_to root_path
end
+ def test_login_remembered
+ user = create(:user)
+
+ post login_path, :params => { :username => user.display_name, :password => "test", :remember_me => "yes" }
+ assert_redirected_to root_path
+
+ assert_equal 28 * 86400, session[:_remember_for]
+ end
+
+ def test_login_not_remembered
+ user = create(:user)
+
+ post login_path, :params => { :username => user.display_name, :password => "test", :remember_me => "0" }
+ assert_redirected_to root_path
+
+ assert_nil session[:_remember_for]
+ end
+
def test_logout_without_referer
post logout_path
assert_redirected_to root_path
assert_select "h1 a[href='#{user_path active_block.user}']", :text => active_block.user.display_name
assert_select "h1 a[href='#{user_path active_block.creator}']", :text => active_block.creator.display_name
assert UserBlock.find(active_block.id).needs_view
+ end
- # Login as the blocked user
- session_for(active_block.user)
+ ##
+ # test clearing needs_view by showing a zero-hour block to the blocked user
+ def test_show_sets_deactivates_at_for_zero_hour_block
+ user = create(:user)
+ session_for(user)
- # Now viewing it should mark it as seen
- get user_block_path(:id => active_block)
- assert_response :success
- assert_not UserBlock.find(active_block.id).needs_view
+ freeze_time do
+ block = create(:user_block, :needs_view, :zero_hour, :user => user)
+ assert block.needs_view
+ assert_nil block.deactivates_at
+
+ travel 1.hour
+
+ get user_block_path(block)
+ assert_response :success
+ block.reload
+ assert_not block.needs_view
+ assert_equal Time.now.utc, block.deactivates_at
+
+ travel 1.hour
+
+ get user_block_path(block)
+ assert_response :success
+ block.reload
+ assert_not block.needs_view
+ assert_equal Time.now.utc - 1.hour, block.deactivates_at
+ end
+ end
+
+ ##
+ # test clearing needs_view by showing a timed block to the blocked user
+ def test_show_sets_deactivates_at_for_timed_block
+ user = create(:user)
+ session_for(user)
+
+ freeze_time do
+ block = create(:user_block, :needs_view, :created_at => Time.now.utc, :ends_at => Time.now.utc + 24.hours, :user => user)
+ assert block.needs_view
+ assert_nil block.deactivates_at
+
+ travel 1.hour
+
+ get user_block_path(block)
+ assert_response :success
+ block.reload
+ assert_not block.needs_view
+ assert_equal Time.now.utc + 23.hours, block.deactivates_at
+
+ travel 1.hour
+
+ get user_block_path(block)
+ assert_response :success
+ block.reload
+ assert_not block.needs_view
+ assert_equal Time.now.utc + 22.hours, block.deactivates_at
+
+ travel 24.hours
+
+ get user_block_path(block)
+ assert_response :success
+ block.reload
+ assert_not block.needs_view
+ assert_equal Time.now.utc - 2.hours, block.deactivates_at
+ end
end
##