From 9abd734720ddad01338b0556ed6210bac5c5b145 Mon Sep 17 00:00:00 2001 From: Lunar Date: Sun, 2 Jun 2013 13:49:49 +0200 Subject: [PATCH] Add join date, fix renewal logic and add ability to specify path to wiki-ca --- Gemfile.lock | 2 + README | 9 ++++ features/list-emails.feature | 31 ++++++++++++ features/pre-commit-hook.feature | 10 ++++ features/pre-receive-hook.feature | 10 ++++ features/step_definitions/commands.rb | 21 ++++++++- features/step_definitions/members.rb | 68 +++++++++++++++++++-------- features/support/env.rb | 7 ++- features/support/fixtures.rb | 7 ++- lib/nos_oignons.rb | 4 +- lib/nos_oignons/member.rb | 39 +++++++++++---- nos_oignons.gemspec | 1 + 12 files changed, 174 insertions(+), 35 deletions(-) diff --git a/Gemfile.lock b/Gemfile.lock index b8a6262..f41add5 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -28,6 +28,7 @@ GEM rspec-expectations (2.13.0) diff-lcs (>= 1.1.3, < 2.0) safe_yaml (0.9.2) + timecop (0.6.1) PLATFORMS ruby @@ -37,3 +38,4 @@ DEPENDENCIES cucumber json (~> 1.7.7) nos_oignons! + timecop diff --git a/README b/README index c31001e..573ec80 100644 --- a/README +++ b/README @@ -31,6 +31,7 @@ Chaque page doit ressembler à : 42 rue du Fleuve 12042 Essaiville email: violette@example.org + joined_on: 2013-05-25 membership_fee_paid_on: 2013-05-25 --- @@ -47,6 +48,8 @@ suivantes : =`email`= L'adresse email du membre. C'est à cette adresse que seront envoyés les messages de l'assemblée générale et les rappels de cotisation. +=`joined_on`= + Date d'adhésion à l'association. =`membership_fee_paid_on`= Date du paiement de la dernière cotisation. @@ -61,6 +64,12 @@ Voici le détail des scripts utilisés. On peut se faire une idée de leurs fonctionalités respectives en lisant les cas d'utilisation dans les fichiers `features/*.feature`. +Le chemin vers la racine du clone du wiki du conseil d'amnisitration est +spécifié par la variable d'environnement `NOS_OIGNONS_BOARD_WIKI_PATH`. Si +cette dernière n'est pas spécifié, les scripts cherchent un répertoire +`Membres` à la racine du Git courant, et si ce n'est pas le cas, dans +le répertoire `wiki-ca` du répertoire parent du Git courant. + `list-email` ------------ diff --git a/features/list-emails.feature b/features/list-emails.feature index 161600f..ebcf76f 100644 --- a/features/list-emails.feature +++ b/features/list-emails.feature @@ -45,3 +45,34 @@ Fonctionnalité: obtenir les emails des membres à jour de cotisations jane@example.org fatima@example.org """ + + Plan du scénario: Renouvellement de la cotisation + Soit une base avec Pierre qui a adhéré le et payé sa dernière cotisation le + Lorsque j'exécute list-emails le + Alors la sortie doit être "" + + Exemples: + | adhésion | cotisation | maintenant | sortie | + | 2012-01-01 | 2012-01-01 | 2012-01-01 | pierre@example.org | + | 2012-01-01 | 2012-01-01 | 2012-12-31 | pierre@example.org | + | 2012-01-01 | 2012-01-01 | 2013-01-01 | pierre@example.org | + | 2012-01-01 | 2012-01-01 | 2013-01-02 | | + | 2012-01-01 | 2012-01-01 | 2013-02-01 | | + | 2012-06-01 | 2012-06-01 | 2013-01-01 | pierre@example.org | + | 2012-06-01 | 2012-06-01 | 2013-06-01 | pierre@example.org | + | 2012-06-01 | 2012-06-01 | 2013-06-02 | | + | 2012-06-01 | 2012-06-01 | 2014-01-01 | | + | 2012-02-29 | 2012-02-29 | 2013-02-01 | pierre@example.org | + | 2012-02-29 | 2012-02-29 | 2013-03-01 | pierre@example.org | + | 2012-02-29 | 2012-02-29 | 2013-03-02 | | + | 2012-02-29 | 2012-02-29 | 2013-12-31 | | + | 2012-12-15 | 2012-12-15 | 2013-01-01 | pierre@example.org | + | 2012-12-15 | 2012-12-15 | 2012-06-01 | pierre@example.org | + | 2012-12-15 | 2012-12-15 | 2013-12-15 | pierre@example.org | + | 2012-12-15 | 2012-12-15 | 2013-12-16 | | + | 2012-12-15 | 2012-12-15 | 2013-12-31 | | + | 2012-12-15 | 2013-12-01 | 2013-12-01 | pierre@example.org | + | 2012-12-15 | 2013-12-01 | 2013-12-15 | pierre@example.org | + | 2012-12-15 | 2013-12-01 | 2014-01-01 | pierre@example.org | + | 2012-12-15 | 2013-12-01 | 2014-12-16 | | + | 2012-12-15 | 2013-12-01 | 2014-12-31 | | diff --git a/features/pre-commit-hook.feature b/features/pre-commit-hook.feature index 8f59ee3..ba47931 100644 --- a/features/pre-commit-hook.feature +++ b/features/pre-commit-hook.feature @@ -45,6 +45,16 @@ Fonctionnalité: pre-commit hook Git Et que je fais un `commit` du nouveau fichier Alors je dois voir comme erreur "pas le bon format" + Scénario: Commit d'une fiche avec une date d'adhésion incensée + Lorsque j'ajoute une fiche avec comme date d'adhésion "2011-99-01" + Et que je fais un `commit` du nouveau fichier + Alors je dois voir comme erreur "pas le bon format" + + Scénario: Commit d'une fiche avec une mauvaise date d'adhésion + Lorsque j'ajoute une fiche avec comme date d'adhésion "janvier 2013" + Et que je fais un `commit` du nouveau fichier + Alors je dois voir comme erreur "pas le bon format" + Scénario: Commit d'une fiche avec une date de cotisation incensée Lorsque j'ajoute une fiche avec comme date de cotisation "2011-99-01" Et que je fais un `commit` du nouveau fichier diff --git a/features/pre-receive-hook.feature b/features/pre-receive-hook.feature index aa7f405..d4d3a40 100644 --- a/features/pre-receive-hook.feature +++ b/features/pre-receive-hook.feature @@ -45,6 +45,16 @@ Fonctionnalité: pre-receive hook Git Et que je pousse la modification Alors je dois voir comme erreur "pas le bon format" + Scénario: Commit d'une fiche avec une date d'adhésion incensée + Lorsque j'ajoute une fiche avec comme date d'adhésion "2011-99-01" + Et que je pousse la modification + Alors je dois voir comme erreur "pas le bon format" + + Scénario: Commit d'une fiche avec une mauvaise date d'adhésion + Lorsque j'ajoute une fiche avec comme date d'adhésion "janvier 2013" + Et que je pousse la modification + Alors je dois voir comme erreur "pas le bon format" + Scénario: Commit d'une fiche avec une date de cotisation incensée Lorsque j'ajoute une fiche avec comme date de cotisation "2011-99-01" Et que je pousse la modification diff --git a/features/step_definitions/commands.rb b/features/step_definitions/commands.rb index 685aa15..26886e6 100644 --- a/features/step_definitions/commands.rb +++ b/features/step_definitions/commands.rb @@ -4,6 +4,19 @@ When /^j'exécute list\-emails$/ do run_simple 'list-emails' end +When /^j'exécute list-emails le (\d+)\-(\d+)\-(\d+)$/ do |year, month, day|$/ + Timecop.travel(Time.new(year, month, day)) do + stdout_io = StringIO.new + begin + $stdout = stdout_io + NosOignons.list_emails! + @stdout = stdout_io.string + ensure + $stdout = STDOUT + end + end +end + When /^j'exécute update-ag-subscribers$/ do run_simple 'update-ag-subscribers' end @@ -17,10 +30,14 @@ Then /^je dois voir comme erreur "(.*?)"$/ do |expected| end Then /^la sortie doit être vide$/ do - assert_exact_output('', all_stdout) + assert_exact_output('', @stdout || all_stdout) end Then /^la sortie doit être:$/ do |expected| # add an extra line feed for nice scenario - assert_exact_output(expected + "\n", all_stdout) + assert_exact_output(expected + "\n", @stdout || all_stdout) +end + +Then /^la sortie doit être "([^"]*)"$/ do |expected| + assert_exact_output(expected, (@stdout || all_stdout).rstrip) end diff --git a/features/step_definitions/members.rb b/features/step_definitions/members.rb index 8bb0330..5bcc39c 100644 --- a/features/step_definitions/members.rb +++ b/features/step_definitions/members.rb @@ -1,37 +1,47 @@ #-*- coding: utf-8 -*- -Given /une base de membres vide$/ do - create_dir 'Membres' +def init_db + @member_db_path = File.join(current_dir, NosOignons::MEMBERS_DB_DIR) + ENV['NOS_OIGNONS_BOARD_WIKI_PATH'] = current_dir + create_dir @member_db_path end -Given /^(?:une base )?avec (\w+)(, à jour de cotisation| qui n'a pas payé sa cotisation cette année)$/ do |name, uptodate| - case uptodate - when ', à jour de cotisation' - # ± 1 month ago - paid_on = (Time.now - 3600*24*30).strftime('%Y-%m-%d') - else - # ± 15 months ago - paid_on = (Time.now - 3600*24*30*15).strftime('%Y-%m-%d') - end +def create_new_member(name, joined_on, paid_on) data = { 'name' => name, 'address' => "At #{name}", 'email' => "#{name.downcase}@example.org", + 'joined_on' => joined_on, 'membership_fee_paid_on' => paid_on } - create_dir 'Membres' + init_db unless @member_db_path file = member_filename_for_id(new_id) write_file file, render_member_file(data) end +Given /une base de membres vide$/ do + init_db +end + +Given /^(?:une base )?avec (\w+)(, à jour de cotisation| qui n'a pas payé sa cotisation cette année)$/ do |name, uptodate| + # ± 15 months ago + joined_on = (Time.now - 3600*24*30*15).strftime('%Y-%m-%d') + case uptodate + when ', à jour de cotisation' + # 30 days ago + paid_on = (Time.now - 3600*24*30).strftime('%Y-%m-%d') + else + paid_on = joined_on + end + create_new_member(name, joined_on, paid_on) +end + +Given /^une base avec (\w+) qui a adhéré le ([0-9-]+) et payé sa dernière cotisation le ([0-9-]+)$/ do |name, joined_on, paid_on| + create_new_member(name, joined_on, paid_on) +end + Given /^une nouvelle adhésion de (\w+)$/ do |name| - data = { 'name' => name, - 'address' => "At #{name}", - 'email' => "#{name.downcase}@example.org", - 'membership_fee_paid_on' => Time.now.strftime('%Y-%m-%d') - } - create_dir 'Membres' - file = member_filename_for_id(new_id) - write_file file, render_member_file(data) + joined_on = Time.now.strftime('%Y-%m-%d') + create_new_member(name, joined_on, joined_on) end When /^j'ajoute une fiche correcte pour une nouvelle adhésion$/ do @@ -68,6 +78,7 @@ When /^j'ajoute une fiche sans email$/ do address: | 21 Jump Street 42000 Synthé + joined_on: 2013-02-20 membership_fee_paid_on: 2013-02-20 --- EOF @@ -81,11 +92,27 @@ When /^j'ajoute une fiche sans nom$/ do address: | 21 Jump Street 42000 Synthé + joined_on: 2013-02-20 membership_fee_paid_on: 2013-02-20 --- EOF end +When /^j'ajoute une fiche avec comme date d'adhésion "([^"]*)"$/ do |date| + @file = member_filename_for_id(new_id) + write_file @file, <<-EOF.gsub(/^ /, '') + --- + name: J. Example + email: joe@example.org + address: | + 21 Jump Street + 42000 Synthé + joined_on: #{date} + membership_fee_paid_on: 2013-04-04 + --- + EOF +end + When /^j'ajoute une fiche avec comme date de cotisation "([^"]*)"$/ do |date| @file = member_filename_for_id(new_id) write_file @file, <<-EOF.gsub(/^ /, '') @@ -95,6 +122,7 @@ When /^j'ajoute une fiche avec comme date de cotisation "([^"]*)"$/ do |date| address: | 21 Jump Street 42000 Synthé + joined_on: 2013-04-04 membership_fee_paid_on: #{date} --- EOF diff --git a/features/support/env.rb b/features/support/env.rb index afaec33..154fc30 100644 --- a/features/support/env.rb +++ b/features/support/env.rb @@ -2,20 +2,25 @@ require 'rubygems' require 'bundler' Bundler.setup +require 'timecop' require 'tmpdir' require 'aruba/cucumber' require 'safe_yaml' SafeYAML::OPTIONS[:default_mode] = :safe +require 'nos_oignons' + Before do ENV['GIT_COMMITTER_NAME'] = ENV['GIT_AUTHOR_NAME'] = 'J. Test' ENV['GIT_COMMITTER_EMAIL'] = ENV['GIT_AUTHOR_EMAIL'] = 'test@example.org' @tmpdir = Dir.mktmpdir('gestion-adh') @dirs = [@tmpdir] - @aruba_io_wait_seconds = 0.5 + @aruba_io_wait_seconds = 1 + @orig_wiki_path = ENV['NOS_OIGNONS_BOARD_WIKI_PATH'] end After do + ENV['NOS_OIGNONS_BOARD_WIKI_PATH'] = @orig_wiki_path FileUtils.remove_entry_secure @tmpdir end diff --git a/features/support/fixtures.rb b/features/support/fixtures.rb index d9d91de..fb06a0c 100644 --- a/features/support/fixtures.rb +++ b/features/support/fixtures.rb @@ -13,6 +13,7 @@ BASE_MEMBERS = YAML.load(< address: | <%= address.gsub(/^/, ' ').rstrip %> email: <%= email %> +joined_on: <%= joined_on %> membership_fee_paid_on: <%= membership_fee_paid_on %> --- diff --git a/lib/nos_oignons.rb b/lib/nos_oignons.rb index 694a87b..028cac9 100644 --- a/lib/nos_oignons.rb +++ b/lib/nos_oignons.rb @@ -34,7 +34,7 @@ module NosOignons IO.popen(['git', 'diff-index', '--cached', '--name-status', against]) do |io| NosOignons::Git.handle_modified_files(io) do |file| - next unless file.start_with?("#{NosOignons::MEMBERS_ROOT}/") + next unless file.start_with?("#{NosOignons::MEMBERS_DB_DIR}/") begin # Use empty ref to get the index NosOignons::Member.read_from_git('', file) @@ -51,7 +51,7 @@ module NosOignons old_value, new_value, ref_name = ref_line.rstrip.split(' ', 3) IO.popen(['git', 'diff', '--name-status', "#{old_value}..#{new_value}"]) do |io| NosOignons::Git.handle_modified_files(io) do |file| - next unless file.start_with?("#{NosOignons::MEMBERS_ROOT}/") + next unless file.start_with?("#{NosOignons::MEMBERS_DB_DIR}/") begin NosOignons::Member.read_from_git(new_value, file) rescue ArgumentError diff --git a/lib/nos_oignons/member.rb b/lib/nos_oignons/member.rb index 9787a63..7e6254e 100644 --- a/lib/nos_oignons/member.rb +++ b/lib/nos_oignons/member.rb @@ -2,21 +2,38 @@ require 'safe_yaml' SafeYAML::OPTIONS[:default_mode] = :safe module NosOignons - MEMBERS_ROOT = 'Membres' - MEMBER_FIELDS = [:name, :address, :email, :membership_fee_paid_on] + MEMBER_FIELDS = [:name, :address, :email, :joined_on, :membership_fee_paid_on] MEMBER_MANDATORY_FIELDS = [:name, :email] + # Directory in the board wiki which holds the member pages + MEMBERS_DB_DIR = 'Membres' class Member < Struct.new(*MEMBER_FIELDS) class << self + def db_path + if ENV['NOS_OIGNONS_BOARD_WIKI_PATH'] + @db_path = File.join(ENV['NOS_OIGNONS_BOARD_WIKI_PATH'], MEMBERS_DB_DIR) + else + return @db_path if @db_path + + git_path = `git rev-parse --show-toplevel`.strip + if File.exists?(File.join(git_path, MEMBERS_DB_DIR)) + @db_path = File.join(git_path, MEMBERS_DB_DIR) + else + @db_path = File.join(File.expand_path('../wiki-ca', path), MEMBERS_DB_DIR) + end + end + @db_path + end + def all - Dir.glob("#{MEMBERS_ROOT}/*.mdwn").sort.collect do |file| + Dir.glob("#{db_path}/*.mdwn").sort.collect do |file| member_id = File.basename(file).gsub(/\.mdwn$/, '') Member.new(member_id) end end def filename_for_id(member_id) - "Membres/%06d.mdwn" % member_id + "#{NosOignons::Member.db_path}/%06d.mdwn" % member_id end def read_from_git(ref, file) @@ -51,15 +68,19 @@ module NosOignons MEMBER_MANDATORY_FIELDS.each do |sym| raise ArgumentError.new('missing mandatory fields') unless self[sym] end - if membership_fee_paid_on && !membership_fee_paid_on.is_a?(Date) - raise ArgumentError.new('membership_fee_paid_on is not a date') + [:joined_on, :membership_fee_paid_on].each do |sym| + if self[sym] && !self[sym].is_a?(Date) + raise ArgumentError.new("#{sym.to_s} is not a date") + end end end def up_to_date? - now = Time.now - last_year = Time.new(now.year - 1, now.month, now.day).to_date - membership_fee_paid_on && last_year < membership_fee_paid_on + return false if !joined_on || !membership_fee_paid_on + + now = Time.now.to_date + expire_on = Time.new(membership_fee_paid_on.year + 1, joined_on.month, joined_on.day).to_date + now <= expire_on end end end diff --git a/nos_oignons.gemspec b/nos_oignons.gemspec index e32ccd1..a858422 100644 --- a/nos_oignons.gemspec +++ b/nos_oignons.gemspec @@ -6,5 +6,6 @@ Gem::Specification.new do |s| s.add_development_dependency 'cucumber' s.add_development_dependency 'aruba' s.add_development_dependency 'json', '~> 1.7.7' + s.add_development_dependency 'timecop' s.add_runtime_dependency 'safe_yaml' end -- 2.39.2