diff --git a/Gemfile b/Gemfile index 3be7cf8c..c04e5041 100644 --- a/Gemfile +++ b/Gemfile @@ -31,18 +31,20 @@ gem 'client_side_validations' gem 'client_side_validations-simple_form' gem 'inherited_resources' gem 'localize_input', git: "git://github.com/bennibu/localize_input.git" -gem 'wikicloth' gem 'daemons' gem 'twitter-bootstrap-rails' gem 'simple-navigation' gem 'simple-navigation-bootstrap' gem 'meta_search' -gem 'acts_as_versioned', git: 'git://github.com/technoweenie/acts_as_versioned.git' # Use this instead of rubygem gem 'acts_as_tree' gem "rails-settings-cached", "0.2.4" gem 'resque' gem 'whenever', require: false # For defining cronjobs, see config/schedule.rb +# we use the git version of acts_as_versioned, and need to include it in this Gemfile +gem 'acts_as_versioned', git: 'git://github.com/technoweenie/acts_as_versioned.git' +gem 'foodsoft_wiki', path: 'lib/foodsoft_wiki' + group :production do gem 'exception_notification' end @@ -78,10 +80,9 @@ group :test do gem 'rspec-rails' gem 'factory_girl_rails', '~> 4.0' gem 'faker' - # version requirements to avoid problem http://stackoverflow.com/questions/18114544 - gem 'capybara', '~> 2.1.0' + gem 'capybara' # webkit and poltergeist don't seem to work yet - gem 'selenium-webdriver', '~> 2.35.1' + gem 'selenium-webdriver' gem 'database_cleaner' gem 'simplecov', require: false # need to include rspec components before i18n-spec or rake fails in test environment diff --git a/Gemfile.lock b/Gemfile.lock index 4c756a49..9783d484 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -18,6 +18,14 @@ GIT acts_as_versioned (0.6.0) activerecord (>= 3.0.9) +PATH + remote: lib/foodsoft_wiki + specs: + foodsoft_wiki (0.0.1) + acts_as_versioned + rails (~> 3.2.15) + wikicloth + GEM remote: https://rubygems.org/ specs: @@ -251,7 +259,7 @@ GEM rspec-mocks (~> 2.14.0) ruby-prof (0.13.0) ruby-rc4 (0.1.5) - rubyzip (0.9.9) + rubyzip (1.0.0) sass (3.2.12) sass-rails (3.2.6) railties (~> 3.2.0) @@ -259,10 +267,10 @@ GEM tilt (~> 1.3) select2-rails (3.5.0) thor (~> 0.14) - selenium-webdriver (2.35.1) + selenium-webdriver (2.37.0) childprocess (>= 0.2.5) multi_json (~> 1.0) - rubyzip (< 1.0.0) + rubyzip (~> 1.0.0) websocket (~> 1.0.4) simple-navigation (3.11.0) activesupport (>= 2.3.2) @@ -308,9 +316,9 @@ GEM rails (>= 3.1) railties (>= 3.1) tzinfo (0.3.38) - uglifier (2.2.1) + uglifier (2.3.0) execjs (>= 0.3.0) - multi_json (~> 1.0, >= 1.0.2) + json (>= 1.8.0) uniform_notifier (1.3.0) vegas (0.1.11) rack (>= 1.0.0) @@ -336,7 +344,7 @@ DEPENDENCIES bullet capistrano (= 2.13.5) capistrano-ext - capybara (~> 2.1.0) + capybara client_side_validations client_side_validations-simple_form coffee-rails (~> 3.2.1) @@ -345,6 +353,7 @@ DEPENDENCIES exception_notification factory_girl_rails (~> 4.0) faker + foodsoft_wiki! haml-rails i18n-js! i18n-spec @@ -369,7 +378,7 @@ DEPENDENCIES ruby-prof sass-rails (~> 3.2.3) select2-rails - selenium-webdriver (~> 2.35.1) + selenium-webdriver simple-navigation simple-navigation-bootstrap simple_form @@ -380,4 +389,3 @@ DEPENDENCIES twitter-bootstrap-rails uglifier (>= 1.0.3) whenever - wikicloth diff --git a/README.md b/README.md index ffe83101..93d7d740 100644 --- a/README.md +++ b/README.md @@ -7,6 +7,8 @@ FoodSoft Web-based software to manage a non-profit food coop (product catalog, ordering, accounting, job scheduling). +A food cooperative is a group of people that buy food from suppliers of their own choosing. A collective do-it-yourself supermarket. Members order their products online and collect them on a specified day. And all put in a bit of work to make that possible. Foodsoft facilitates the process. + If you're a food coop considering to use foodsoft, please have a look at the [wiki page for foodcoops](https://github.com/foodcoops/foodsoft/wiki/For-foodcoops). When you'd like to experiment with or develop foodsoft, you can read [how to set it up](https://github.com/foodcoops/foodsoft/blob/master/doc/SETUP_DEVELOPMENT.md) on your own computer. More information about using this software and contributing can be found on the [wiki](https://github.com/foodcoops/foodsoft/wiki). diff --git a/app/controllers/group_orders_controller.rb b/app/controllers/group_orders_controller.rb index 31d1178a..5869d3ff 100644 --- a/app/controllers/group_orders_controller.rb +++ b/app/controllers/group_orders_controller.rb @@ -65,7 +65,7 @@ class GroupOrdersController < ApplicationController private # Returns true if @current_user is member of an Ordergroup. - # Used as a :before_filter by OrderingController. + # Used as a :before_filter by OrdersController. def ensure_ordergroup_member @ordergroup = @current_user.ordergroup if @ordergroup.nil? diff --git a/app/controllers/memberships_controller.rb b/app/controllers/memberships_controller.rb deleted file mode 100644 index e8373675..00000000 --- a/app/controllers/memberships_controller.rb +++ /dev/null @@ -1,33 +0,0 @@ -class MembershipsController < ApplicationController - before_filter :authenticate_membership_or_admin - - def add_member - user = User.find(params[:user_id]) - Membership.create(:group => @group, :user => user) - redirect_to :action => 'reload', :id => @group - end - - def drop_member - begin - Membership.find(params[:membership_id]).destroy - if User.find(@current_user.id).role_admin? - redirect_to :action => 'reload', :id => @group - else - # If the user drops himself from admin group - flash[:notice] = MESG_NO_ADMIN_ANYMORE - render(:update) {|page| page.redirect_to :controller => "index"} - end - rescue => error - flash[:error] = error.to_s - redirect_to :action => 'reload', :id => @group - end - end - - def reload - render :update do |page| - page.replace_html 'members', :partial => 'shared/memberships/current_members', :object => @group - page.replace_html 'non_members', :partial => 'shared/memberships/non_members', :object => @group - end - end - -end diff --git a/app/controllers/orders_controller.rb b/app/controllers/orders_controller.rb index d52ae698..578327f1 100644 --- a/app/controllers/orders_controller.rb +++ b/app/controllers/orders_controller.rb @@ -48,6 +48,9 @@ class OrdersController < ApplicationController end send_data pdf.to_pdf, filename: pdf.filename, type: 'application/pdf' end + format.text do + send_data text_fax_template, filename: @order.name+'.txt', type: 'text/plain' + end end end @@ -101,12 +104,14 @@ class OrdersController < ApplicationController rescue => error redirect_to orders_url, alert: I18n.t('errors.general_msg', :msg => error.message) end + + protected # Renders the fax-text-file # e.g. for easier use with online-fax-software, which don't accept pdf-files + # TODO move to text template def text_fax_template - order = Order.find(params[:id]) - supplier = order.supplier + supplier = @order.supplier contact = FoodsoftConfig[:contact].symbolize_keys text = I18n.t('orders.fax.heading', :name => FoodsoftConfig[:name]) text += "\n#{Supplier.human_attribute_name(:customer_number)}: #{supplier.customer_number}" unless supplier.customer_number.blank? @@ -117,15 +122,13 @@ class OrdersController < ApplicationController text += "****** " + I18n.t('orders.fax.articles') + "\n\n" text += I18n.t('orders.fax.number') + " " + I18n.t('orders.fax.amount') + " " + I18n.t('orders.fax.name') + "\n" # now display all ordered articles - order.order_articles.ordered.all(:include => [:article, :article_price]).each do |oa| + @order.order_articles.ordered.all(:include => [:article, :article_price]).each do |oa| number = oa.article.order_number (8 - number.size).times { number += " " } quantity = oa.units_to_order.to_i.to_s quantity = " " + quantity if quantity.size < 2 text += "#{number} #{quantity} #{oa.article.name}\n" end - send_data text, - :type => 'text/plain; charset=utf-8; header=present', - :disposition => "attachment; filename=#{order.name}" + text end end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 43a36fa5..59994432 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -78,14 +78,14 @@ module ApplicationHelper # When the 'short' option is true, abbreviations will be used: # When there is a non-empty model attribute 'foo', it looks for # the model attribute translation 'foo_short' and use that as - # heading, with an acronym title of 'foo'. + # heading, with an abbreviation title of 'foo'. # Other options are passed through to I18n. def heading_helper(model, attribute, options = {}) i18nopts = options.select {|a| !['short'].include?(a) } s = model.human_attribute_name(attribute, i18nopts) if options[:short] sshort = model.human_attribute_name("#{attribute}_short".to_sym, options.merge({defaults: ''})) - s = raw "#{sshort}" unless sshort.empty? + s = raw "#{sshort}" unless sshort.empty? end s end diff --git a/app/models/article.rb b/app/models/article.rb index a3b4af33..0c809784 100644 --- a/app/models/article.rb +++ b/app/models/article.rb @@ -106,7 +106,7 @@ class Article < ActiveRecord::Base # to get the correspondent shared article def shared_article - @shared_article ||= self.supplier.shared_supplier.shared_articles.find_by_number(self.order_number) + @shared_article ||= self.supplier.shared_supplier.shared_articles.find_by_number(self.order_number) rescue nil end # convert units in foodcoop-size diff --git a/app/models/order_article.rb b/app/models/order_article.rb index bd90706b..3eb97aea 100644 --- a/app/models/order_article.rb +++ b/app/models/order_article.rb @@ -90,7 +90,8 @@ class OrderArticle < ActiveRecord::Base end def ordered_quantities_equal_to_group_orders? - (units_to_order * price.unit_quantity) == group_orders_sum[:quantity] + # the rescue is a workaround for units_to_order not being defined in integration tests + (units_to_order * price.unit_quantity) == group_orders_sum[:quantity] rescue false end # Updates order_article and belongings during balancing process diff --git a/app/models/user.rb b/app/models/user.rb index f90f9602..3119e29d 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -17,7 +17,6 @@ class User < ActiveRecord::Base has_many :assignments, :dependent => :destroy has_many :tasks, :through => :assignments has_many :send_messages, :class_name => "Message", :foreign_key => "sender_id" - has_many :pages, :foreign_key => 'updated_by' has_many :created_orders, :class_name => 'Order', :foreign_key => 'created_by_user_id', :dependent => :nullify attr_accessor :password, :settings_attributes diff --git a/app/views/articles/_destroy_active_article.haml b/app/views/articles/_destroy_active_article.haml index 73c59e1c..90dcfae2 100644 --- a/app/views/articles/_destroy_active_article.haml +++ b/app/views/articles/_destroy_active_article.haml @@ -1,3 +1,3 @@ %tr.edit_inline{:id=> "edit_"+@article.id.to_s} %td{:colspan=>"10"} - = t('.note', article: h(@article.name), drop_link: link_to(t('.drop'), :controller => 'orders', :action => 'edit', :id => @order)).html_safe + = t('.note', article: h(@article.name), drop_link: link_to(t('.drop'), edit_order_path(@order))).html_safe diff --git a/app/views/group_orders/_form.html.haml b/app/views/group_orders/_form.html.haml index 14ca9303..a0b11791 100644 --- a/app/views/group_orders/_form.html.haml +++ b/app/views/group_orders/_form.html.haml @@ -9,7 +9,14 @@ // create List for search-feature (using list.js, http://listjs.com) var listjsResetPlugin = ['reset', {highlightClass: 'btn-primary'}]; var listjsDelayPlugin = ['delay', {delayedSearchTime: 500}]; - new List(document.body, { valueNames: ['name'], engine: 'unlist', plugins: [listjsResetPlugin, listjsDelayPlugin] }); + new List(document.body, { + valueNames: ['name'], + engine: 'unlist', + plugins: [listjsResetPlugin, listjsDelayPlugin], + // make large pages work too (as we don't have paging - articles may disappear!) + page: 10000, + indexAsync: true + }); }); - title t('.title'), false diff --git a/app/views/home/_start_nav.haml b/app/views/home/_start_nav.haml index 4f7f1b5c..346aa67a 100644 --- a/app/views/home/_start_nav.haml +++ b/app/views/home/_start_nav.haml @@ -4,7 +4,7 @@ %li.nav-header= t '.foodcoop' %li= link_to t('.members'), foodcoop_users_path %li= link_to t('.tasks'), user_tasks_path - %li= link_to t('.write_message'), :controller => "messages", :action => "new" + %li= link_to t('.write_message'), new_message_path - has_ordergroup = !@current_user.ordergroup.nil? - has_orders_role = @current_user.role_orders? diff --git a/app/views/home/ordergroup.html.haml b/app/views/home/ordergroup.html.haml index 1fe79cbf..213ef0c9 100644 --- a/app/views/home/ordergroup.html.haml +++ b/app/views/home/ordergroup.html.haml @@ -4,16 +4,14 @@ .span4 %h2= @ordergroup.name .well + - unless @ordergroup.description.blank? + %p= @ordergroup.description %p - %b= t '.description' - = @ordergroup.description - %p - %b= t '.funds' + %b= Ordergroup.human_attribute_name(:available_funds) + ':' = number_to_currency(@ordergroup.get_available_funds()) - %h2= t '.people' - %ul - - for membership in @ordergroup.memberships - %li= show_user membership.user + %p + %b= Ordergroup.human_attribute_name(:user_tokens) + ':' + = @ordergroup.memberships.map{|m| show_user m.user}.join(', ') = link_to t('.invite'), new_invite_path(:id => @ordergroup), :remote => true, class: 'btn btn-primary' .span8 %h2= t('.account_summary') diff --git a/app/views/home/profile.html.haml b/app/views/home/profile.html.haml index 3b0a8abb..0b0364a1 100644 --- a/app/views/home/profile.html.haml +++ b/app/views/home/profile.html.haml @@ -5,7 +5,7 @@ %h3 = h(t('.user.title', user: show_user)) %small= t '.user.since', when: distance_of_time_in_words(Time.now, @current_user.created_on) - = simple_form_for(@current_user, :url => { :action => 'update_profile'}) do |f| + = simple_form_for(@current_user, :url => update_profile_path) do |f| = render :partial => 'shared/user_form_fields', :locals => {:f => f} .form-actions = submit_tag t('ui.save'), class: 'btn' diff --git a/app/views/layouts/application1.html.haml b/app/views/layouts/application1.html.haml deleted file mode 100644 index c52e8003..00000000 --- a/app/views/layouts/application1.html.haml +++ /dev/null @@ -1,32 +0,0 @@ -!!! -%html - %head - %meta{"http-equiv" => "content-type", :content => "text/html;charset=UTF-8"} - %title= t '.title', title: (yield(:title) or controller.controller_name) - = stylesheet_link_tag 'application' - = stylesheet_link_tag "print", :media => "print" - - = javascript_include_tag 'application' - = csrf_meta_tags - = yield(:head) - %body - #logininfo= render :partial => 'shared/loginInfo' - - #header - #logo - = link_to root_path do - = t('layouts.logo').html_safe - %span{:style => "color:white; font-size:45%; letter-spacing: -1px;"}= FoodsoftConfig[:name] - #nav= render :partial => 'layouts/main_tabnav' - - #main - #content - - flash.each do |name, msg| - = content_tag :h3, msg, :id => "flash#{name.to_s.camelize}", :class => "flash #{name}" - #loader{:style => "display:none;"}= image_tag("loader.gif", :border => 0) - - if show_title? - %h1= yield(:title) - = yield - #ajax_box(style="display:none") diff --git a/app/views/login/forgot_password.html.haml b/app/views/login/forgot_password.html.haml index 568ac258..c299f0ae 100644 --- a/app/views/login/forgot_password.html.haml +++ b/app/views/login/forgot_password.html.haml @@ -1,6 +1,6 @@ - title t('.title') = t('.body').html_safe -= simple_form_for User.new, url: {action: 'reset_password'} do |form| += simple_form_for User.new, url: reset_password_path do |form| = form.input :email .form-actions = form.submit t('.submit'), class: 'btn' diff --git a/app/views/login/new_password.html.haml b/app/views/login/new_password.html.haml index f3fe19e5..2aa21e57 100644 --- a/app/views/login/new_password.html.haml +++ b/app/views/login/new_password.html.haml @@ -1,6 +1,6 @@ - title t('.title') = raw t('.body', user: h(show_user(@user))) -= simple_form_for @user, :url => {:action => 'update_password', :id => @user.id, :token => @user.reset_password_token} do |form| += simple_form_for @user, :url => update_password_path(@user.id, :token => @user.reset_password_token) do |form| = form.input :password = form.input :password_confirmation .form-actions diff --git a/app/views/orders/show.html.haml b/app/views/orders/show.html.haml index 2a34807d..865a83c8 100644 --- a/app/views/orders/show.html.haml +++ b/app/views/orders/show.html.haml @@ -50,7 +50,7 @@ %li= order_pdf(@order, :articles, t('.download.article_pdf')) %li= order_pdf(@order, :matrix, t('.download.matrix_pdf')) %li= order_pdf(@order, :fax, t('.download.fax_pdf')) - %li= link_to t('.download.fax_txt'), {action: 'text_fax_template', id: @order }, {title: t('.download.download_file')} + %li= link_to t('.download.fax_txt'), order_path(@order, format: :txt), {title: t('.download.download_file')} %section#articles_table = render 'articles', order: @order diff --git a/app/views/shared/_auto_complete_articles.html.haml b/app/views/shared/_auto_complete_articles.html.haml deleted file mode 100644 index 84dda2d6..00000000 --- a/app/views/shared/_auto_complete_articles.html.haml +++ /dev/null @@ -1,4 +0,0 @@ -%ul.autocomplete - - for article in @articles - - supplier = @supplier ? "" : " - #{truncate(article.supplier.name)}" - %li{:id => article.id.to_s}= "#{article.name} (#{article.unit_quantity} * #{article.unit} | #{number_to_currency(article.price)}#{supplier})" diff --git a/app/views/shared/_auto_complete_users.rhtml b/app/views/shared/_auto_complete_users.rhtml deleted file mode 100644 index 8a3a6ed4..00000000 --- a/app/views/shared/_auto_complete_users.rhtml +++ /dev/null @@ -1,5 +0,0 @@ - diff --git a/app/views/shared/_loginInfo.haml b/app/views/shared/_loginInfo.haml deleted file mode 100644 index 8ca136ec..00000000 --- a/app/views/shared/_loginInfo.haml +++ /dev/null @@ -1,9 +0,0 @@ -%ul - %li - = image_tag 'b_user.png' , :size => '7x10', :border => 0, :alt => t('.profile') - = link_to h(@current_user.nick), my_profile_path, { :title => t('.edit_profile') } - - if FoodsoftConfig[:homepage] - %li= link_to FoodsoftConfig[:name], FoodsoftConfig[:homepage], { :title => t('.homepage_title') } - %li= link_to t('.help'), FoodsoftConfig[:help_url] - %li= link_to t('.feedback.title'), new_feedback_path, :title => t('.feedback.desc') - %li= link_to t('.logout'), logout_path diff --git a/app/views/shared/memberships/_current_members.rhtml b/app/views/shared/memberships/_current_members.rhtml deleted file mode 100644 index 18939041..00000000 --- a/app/views/shared/memberships/_current_members.rhtml +++ /dev/null @@ -1,21 +0,0 @@ -<% if flash[:error] %> -

<%= flash[:error] %>

- <%= javascript_tag("new Effect.Highlight('flashError', {delay:0.8, duration:1});") -%> -<% end %> - -<% memberships = @group.memberships - if memberships.size != 0 %> - - <% else %> -

<%= t('.no_members', group: @group.name) %>

- <% end %> diff --git a/app/views/shared/memberships/_members.rhtml b/app/views/shared/memberships/_members.rhtml deleted file mode 100644 index 55a35452..00000000 --- a/app/views/shared/memberships/_members.rhtml +++ /dev/null @@ -1,23 +0,0 @@ -

<%=h t('.title', group: @group.name) %>

-

- <%= t('.desc', link: remote_link_to(t('.invite'), :url => new_invite_path(:id => @group))).html_safe %> -

-
-
-

<%= t('.already_members') %>

-
-
- <%=render :partial => 'shared/memberships/current_members' %> -
-
-
-
-

<%= t('.no_members_yet') %>

-
-
- <%= render :partial => 'shared/memberships/non_members' %> - <%= remote_link_to(t('.invite_someone'), :url => new_invite_path(:id => @group)) %> -
-
- - diff --git a/app/views/shared/memberships/_non_members.rhtml b/app/views/shared/memberships/_non_members.rhtml deleted file mode 100644 index e741a13a..00000000 --- a/app/views/shared/memberships/_non_members.rhtml +++ /dev/null @@ -1,11 +0,0 @@ - diff --git a/app/views/tasks/_archive_tasks.html.haml b/app/views/tasks/_archive_tasks.html.haml index 46250ddd..9ece4d05 100644 --- a/app/views/tasks/_archive_tasks.html.haml +++ b/app/views/tasks/_archive_tasks.html.haml @@ -13,5 +13,5 @@ - @tasks.each do |task| %tr %td= task.due_date unless task.due_date.nil? - %td= link_to t('.task_format', name: task.name, duration: task.duration), :controller => "tasks", :action => "show", :id => task + %td= link_to t('.task_format', name: task.name, duration: task.duration), task_path(task) %td= task_assignments task diff --git a/config/locales/de.yml b/config/locales/de.yml index badf52ae..6c776a12 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -853,10 +853,7 @@ de: no_ordergroups: Leider bist Du kein Mitglied einer Bestellgruppe ordergroup: account_summary: Kontoauszug - description: Beschreibung - funds: ! 'Verfügbares Guthaben:' invite: Neue Person einladen - people: Personen search: Suchen ... title: Meine Bestellgruppe ordergroup_cancelled: Du bist jetzt kein Mitglied der Gruppe %{group} mehr. @@ -906,8 +903,6 @@ de: ordering: confirm_change: Änderungen an dieser Bestellung gehen verloren, wenn zu einer anderen Bestellung gewechselt wird. Möchtest Du trotzdem wechseln? layouts: - application1: - title: Foodsoft - %{title} email: footer: ! '-- @@ -1367,28 +1362,6 @@ de: search_user: Nach Nutzerin suchen title: Wöchentliche Jobs user_not_found: Keine Nutzerin gefunden - loginInfo: - edit_profile: Profil bearbeiten - feedback: - desc: Fehler gefunden? Vorschlag? Idee? Kritik? - title: Feedback - help: Hilfe - homepage_title: Foodcoop Homepage besuchen - logout: Abmelden - profile: Profil - memberships: - current_members: - drop: entfernen - no_members: ! '%{group} hat keine Mitglieder.' - members: - already_members: Sind schon Mitglieder - desc: Hier kannst Du Mitglieder der Gruppe verwalten oder ein neues Foodcoop-Mitglied in die Gruppe %{link}. - invite: einladen - invite_someone: Person einladen - no_members_yet: Sind noch keine Mitglieder - title: Mitglieder von %{group} - non_members: - add: hinzufügen open_orders: ending: Ende no_open_orders: Derzeit gibt es keine laufenden Bestellungen @@ -1416,7 +1389,6 @@ de: name: Bitte ändern edit_stock_article: price: - supplier: supplier: min_order_quantity: Die Mindestbestellmenge wird während der Bestellung angezeigt und soll motivieren task: diff --git a/config/locales/en.yml b/config/locales/en.yml index 5e547a03..63b87afc 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -646,7 +646,7 @@ en: title: Invoice %{number} order_articles: edit: - stock_alert: + stock_alert: The price of stock articles cannot be changed! title: Update article new: title: Add delivered article to order @@ -858,10 +858,7 @@ en: no_ordergroups: You are unfortunately not a member of an ordergroup. ordergroup: account_summary: Account Statement - description: description - funds: ! 'Available credit:' invite: Invite a new Person - people: People search: Search ... title: My ordergroup ordergroup_cancelled: You cancelled membership of the group %{group}. @@ -911,8 +908,6 @@ en: ordering: confirm_change: Modifications to this order will be lost when you change the order. Do you want to lose the changes you made and continue? layouts: - application1: - title: Foodsoft - %{title} email: footer: ! '-- @@ -1372,28 +1367,6 @@ en: search_user: Search user title: Weekly jobs user_not_found: No user found - loginInfo: - edit_profile: Edit profile - feedback: - desc: Found a bug? Suggestions? Review? - title: Feedback - help: Help - homepage_title: Visit Foodcoop Homepage - logout: Logout - profile: Profile - memberships: - current_members: - drop: remove - no_members: ! '%{group} has no members.' - members: - already_members: Are already members - desc: Here you can manage members of the group or invite a new Foodcoop-member to the group %{link}. - invite: invite - invite_someone: Invite someone - no_members_yet: Are not members yet - title: Members of %{group} - non_members: - add: add open_orders: ending: Ending no_open_orders: There are no current orders @@ -1421,7 +1394,6 @@ en: name: Please modify edit_stock_article: price: - supplier: supplier: min_order_quantity: The minimum amount which has to be orderd will be shown during the order process and should motivate ordering task: diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 0a495014..f5e54531 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -879,10 +879,7 @@ fr: no_ordergroups: Tu ne fais encore partie d'aucune cellule ordergroup: account_summary: Relevé de compte - description: Description - funds: ! 'Crédit disponible:' invite: Engrainer une nouvelle personne - people: Personnes search: Rechercher ... title: Ta cellule ordergroup_cancelled: Tu ne fais plus partie de la cellule %{group}. @@ -932,8 +929,6 @@ fr: ordering: confirm_change: layouts: - application1: - title: Foodsoft - %{title} email: footer: ! '-- @@ -1374,28 +1369,6 @@ fr: search_user: Rechercher par utilisatrice title: Boulots hebdomadaires user_not_found: Aucune utilisatrice n'a été trouvée. - loginInfo: - edit_profile: Modifier le profil - feedback: - desc: Tu as détecté une erreur? Tu as des propositions, des idées, des critiques? - title: Retours - help: Aide - homepage_title: Vers la page d'accueil de la bouffecoop - logout: Te déconnecter - profile: Profil - memberships: - current_members: - drop: désinscrire - no_members: ! '%{group} n''a aucun membre pour le moment.' - members: - already_members: Sont déjà membre - desc: Sur cette page, tu peux gérer les membres de l'équipe, et aussi %{link} un nouveau membre. - invite: engrainer - invite_someone: Inviter quelqu'unE - no_members_yet: Ne sont pas encore membre - title: Membre de %{group} - non_members: - add: ajouter open_orders: ending: Clôture le no_open_orders: Il n'y a aucune commande en cours en ce moment @@ -1423,7 +1396,6 @@ fr: name: Merci de modifier edit_stock_article: price: - supplier: supplier: min_order_quantity: La quantité minimum à commander est affichée pendant la commande et doit motiver task: diff --git a/config/locales/nl.yml b/config/locales/nl.yml index fba0e912..02fa13d4 100644 --- a/config/locales/nl.yml +++ b/config/locales/nl.yml @@ -26,15 +26,15 @@ nl: description: Omschrijving name: Naam delivery: - delivered_on: - note: - supplier: + delivered_on: Leverdatum + note: Notitie + supplier: Leverancier financial_transaction: amount: bedrag note: notitie group_order_article: - ordergroup_id: - result: + ordergroup_id: Huishouden + result: Hoeveelheid invoice: amount: Bedrag date: Factuurdatum @@ -47,12 +47,12 @@ nl: paid_on: Betaald op supplier: Leverancier message: - body: - group_id: - private: - recipient_tokens: - sent_to_all: - subject: + body: Bericht + group_id: Groep + private: Privé + recipient_tokens: Geadresseerden + sent_to_all: Aan alle leden sturen + subject: Onderwerp order: ends: Eindigt op note: Notitie @@ -71,22 +71,22 @@ nl: name: Naam user_tokens: Leden page: - body: + body: Bericht parent_id: - title: + title: Titel stock_article: price: Prijs quantity: Aantal quantity_available: Beschikbaar supplier: Leverancier stock_taking: - date: - note: + date: Datum + note: Notitie supplier: address: Adres contact_person: Contactpersoon customer_number: Klantnummer - customer_number_short: + customer_number_short: Klantnr. delivery_days: Bezorgdagen email: Email fax: Fax @@ -99,14 +99,14 @@ nl: phone2: Telefoon 2 url: Homepage task: - description: - done: - due_date: - duration: - name: - required_users: - user_list: - workgroup: + description: Beschrijving + done: Gedaan? + due_date: Voor wanneer? + duration: Tijdsduur + name: Naam + required_users: Aantal + user_list: Verantwoordelijken + workgroup: Werkgroep user: email: Email first_name: Voornaam @@ -123,7 +123,7 @@ nl: workgroup: description: Omschrijving name: Naam - next_weekly_tasks_number: + next_weekly_tasks_number: Hoeveel weken vooruit moet de taak zichtbaar zijn? role_admin: Beheer role_article_meta: Artikelen role_finance: Financiën @@ -297,7 +297,7 @@ nl: error_parse: ! '%{msg} ... in regel %{line}' error_update: ! 'Er trad een fout op bij het bijwerken van artikel ''%{article}'': %{msg}' parse_upload: - notice: ! '%{count} artikel zijn geanalyseerd' + notice: ! '%{count} artikelen zijn geanalyseerd' sync: notice: Catalogus is bijgewerkt shared_alert: ! '%{supplier} is niet aan een externe database gekoppeld' @@ -393,9 +393,9 @@ nl: title: form: actions: - article: - category: - create_from_blank: + article: Artikel + category: Categorie + create_from_blank: Nieuwe artikel invoeren create_stock_article: price: quantity: @@ -639,7 +639,7 @@ nl: title: Factuur %{number} order_articles: edit: - stock_alert: + stock_alert: De prijs van voorraadartikelen kan niet aangepast worden! title: Artikel bijwerken new: title: Geleverd artikel aan bestelling toevoegen @@ -850,10 +850,7 @@ nl: no_ordergroups: Jammergenoeg ben je niet aangesloten bij een huishouden. ordergroup: account_summary: Rekeningafschrift - description: Omschrijving - funds: ! 'Beschikbaar krediet:' invite: Iemand uitnodigen - people: Personen search: Zoeken ... title: Mijn huishouden ordergroup_cancelled: Je bent geen lid meer van de groep %{group}. @@ -903,8 +900,6 @@ nl: ordering: confirm_change: layouts: - application1: - title: Foodsoft - %{title} email: footer: ! '-- @@ -1279,7 +1274,7 @@ nl: price: Totaalprijs articles_by_groups: fc_price: FC-Prijs - fc_price_desc: Prijs inclusief belasting, borg en foodcoop-toeslag + fc_price_desc: Prijs inclusief belasting, statiegeld en foodcoop marge name: Naam price: Totaalprijs unit: Eenheid @@ -1301,28 +1296,6 @@ nl: search_user: Gebruiker zoeken title: Wekelijkse taken user_not_found: Geen gebruiker gevonden - loginInfo: - edit_profile: Profiel aanpassen - feedback: - desc: Fout gevonden? Opmerking? Idee? - title: Feedback - help: Help - homepage_title: Foodcoop startpagina bezoeken - logout: Uitloggen - profile: Profiel - memberships: - current_members: - drop: verwijderen - no_members: ! '%{group} heeft geen leden.' - members: - already_members: Zijn al lid - desc: - invite: uitnodiging - invite_someone: Iemand uitnodigen - no_members_yet: Zijn nog geen lid - title: Leden van %{group} - non_members: - add: toevoegen open_orders: ending: Einde no_open_orders: Er zijn momenteel geen lopende bestellingen. @@ -1350,7 +1323,6 @@ nl: name: edit_stock_article: price: - supplier: supplier: min_order_quantity: task: diff --git a/config/navigation.rb b/config/navigation.rb index 74b76bbe..49a3293d 100644 --- a/config/navigation.rb +++ b/config/navigation.rb @@ -3,6 +3,11 @@ SimpleNavigation::Configuration.run do |navigation| + # allow engines to add to the menu - https://gist.github.com/mjtko/4873ee0c112b6bd646f8 + engines = Rails.application.railties.engines.select { |e| e.respond_to?(:navigation) } + # to include an engine but keep it from modifying the menu: + #engines.reject! { |e| e.instance_of? FoodsoftMyplugin::Engine } + navigation.items do |primary| primary.dom_class = 'nav' @@ -16,11 +21,6 @@ SimpleNavigation::Configuration.run do |navigation| subnav.item :tasks, I18n.t('navigation.tasks'), tasks_path, id: nil end - primary.item :wiki, I18n.t('navigation.wiki.title'), '#', id: nil do |subnav| - subnav.item :wiki_home, I18n.t('navigation.wiki.home'), wiki_path, id: nil - subnav.item :all_pages, I18n.t('navigation.wiki.all_pages'), all_pages_path, id: nil - end - primary.item :orders, I18n.t('navigation.orders.title'), '#', id: nil do |subnav| subnav.item :ordering, I18n.t('navigation.orders.ordering'), group_orders_path, id: nil subnav.item :ordering_archive, I18n.t('navigation.orders.archive'), archive_group_orders_path, id: nil @@ -47,6 +47,8 @@ SimpleNavigation::Configuration.run do |navigation| subnav.item :ordergroups, I18n.t('navigation.admin.ordergroups'), admin_ordergroups_path, id: nil subnav.item :workgroups, I18n.t('navigation.admin.workgroups'), admin_workgroups_path, id: nil end + + engines.each { |e| e.navigation(primary, self) } end end diff --git a/config/routes.rb b/config/routes.rb index 533d2d97..655a1038 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -18,27 +18,20 @@ Foodsoft::Application.routes.draw do match '/login' => 'sessions#new', :as => 'login' match '/logout' => 'sessions#destroy', :as => 'logout' - get '/login/forgot_password' => 'login#forgot_password', as: :forgot_password - get '/login/new_password' => 'login#new_password', as: :new_password + get '/login/forgot_password' => 'login#forgot_password', as: :forgot_password + post '/login/reset_password' => 'login#reset_password', as: :reset_password + get '/login/new_password' => 'login#new_password', as: :new_password + get '/login/update_password' => 'login#update_password', as: :update_password match '/login/accept_invitation/:token' => 'login#accept_invitation', as: :accept_invitation resources :sessions, :only => [:new, :create, :destroy] ########### User specific match '/home/profile' => 'home#profile', :as => 'my_profile' + put '/home/update_profile' => 'home#update_profile', :as => 'update_profile' match '/home/ordergroup' => 'home#ordergroup', :as => 'my_ordergroup' match '/home/cancel_membership' => 'home#cancel_membership', :as => 'cancel_membership' - ############ Wiki - - resources :pages do - get :all, :on => :collection - get :version, :on => :member - get :revert, :on => :member - end - match '/wiki/:permalink' => 'pages#show', :as => 'wiki_page' # , :constraints => {:permalink => /[^\s]+/} - match '/wiki' => 'pages#show', :defaults => {:permalink => 'Home'}, :as => 'wiki' - ############ Orders, ordering resources :orders do @@ -191,8 +184,5 @@ Foodsoft::Application.routes.draw do resources :users, :only => [:index] - # TODO: This is very error prone. Better deactivate this catch all route - match ':controller(/:action(/:id))(.:format)' - end # End of /:foodcoop scope end diff --git a/db/migrate/20090325175756_create_pages.foodsoft_wiki_engine.rb b/db/migrate/20090325175756_create_pages.foodsoft_wiki_engine.rb new file mode 100644 index 00000000..dc8cb3bc --- /dev/null +++ b/db/migrate/20090325175756_create_pages.foodsoft_wiki_engine.rb @@ -0,0 +1,24 @@ +# This migration comes from foodsoft_wiki_engine (originally 20090325175756) +class CreatePages < ActiveRecord::Migration + def self.up + create_table :pages do |t| + t.string :title + t.text :body + t.string :permalink + t.integer :lock_version, :default => 0 + t.integer :updated_by + t.integer :redirect + t.integer :parent_id + + t.timestamps + end + add_index :pages, :title + add_index :pages, :permalink + Page.create_versioned_table # Automaticly creates pages_versions table + end + + def self.down + drop_table :pages + Page.drop_versioned_table + end +end diff --git a/doc/BESTELLEN.md b/doc/BESTELLEN.md new file mode 100644 index 00000000..092827eb --- /dev/null +++ b/doc/BESTELLEN.md @@ -0,0 +1,93 @@ + +# Bestellen +Das Bestellen ist der Hauptteil dieser Software und ein wenig kompliziert. +Hier starte ich den Versuch die Programmlogik in Text umzusetzen und +verweise auf die enstprechenden Controller bzw. Modelle. +Der relevante Controller ist `OrdersController`. + +## Bestellung "in Netz stellen" +Darunter verstehen wir die Auswahl von Artikeln eines bestimmten Lieferanten fuer eine zeitlich begrenzte +Bestellung im Internet. Die relevanten Methoden sind `OrdersController#newOrder` und folgende. +Jede Bestellung wird durch die Klasse Order abgebildet. + +Die zugehoerigen Artikel werden duch die Klasse `OrderArticle` mit den Artikeln verknuepft. +Dabei werden auch die Attribute `quantity`, `tolerance` und `quantity_to_order` gespeichert. +Diese Mengen repraesentieren die Gesamtbestellung, also alle Bestellgruppen. + +## Eine Bestellgruppe bestellt... +Die Methode `OrdersController#order` schickt uns die Bestellenseite. Mit dieser +Oberflaeche koennen die Bestellgruppena die vorher ausgewaehlten Artikel +bestellen. Mittels den Buttons werden dabei live, also clientseitig, die +Preise ermittelt und der Gesamtpreis berechnet. Ist der Gesamtpreis groeßer als +der aktuelle Gruppenkontostand, so wird die Preisspalte rot unterlegt und die +Bestellung kann nicht gespeichert werden. + +## (gruppen)-Bestellung wird gespeichert + +Die Gruppenbestellung wird durch die Tabelle `group_oders` (`GroupOrder`) +abgebildet, bzw. die Bestellung und Bestellgruppe wird dort verknuepft. + +Die bestellten Artikel der Bestellgruppe werden durch die Tabelle `group_order_articles` +(`GroupOrderArticle`) registriert. Dort werden nun die Modelle GroupOrder +und OrderArticle miteinander verbunden. + +Bei jeder Bestellung wird außerdem die Summe der Menge, Toleranz in `GroupOrderArticle` +abgelegt. Allerdings muss jede Aenderung dieser Mengen mit protokolliert werden. +Dies ist wichtig, weil spaeter die Zuteilung der Einheiten pro bestellten Artikel +nach der chronologischen Reihenfolge erfolgt. (s.u.) +Das passiert dann in der Tabelle `group_order_article_quantities` +(`GroupOrderArticleQuantity`). + +## Aenderunug einer Bestellung + +Knifflig ist die Aenderung einer gruppenbestellung, weil die zeitliche +Reihenfolge dabei nicht durcheinander geraten darf. +Wir unterscheiden dehalb zwei Faelle: + +### Erhoehe die Menge des Arikels. +Jetzt wird eine Zeile in `group_order_article_quantities` angelegt. +und zwar mit genau den Mengen, die zusatzlich bestellt wurden. +Quantity und Tolerance funktionieren analog. + +Beispiel: +* Urspruenglich bestellt: 2(2) um 17uhr. +* Erhoehe Bestellung auf 4(2) um 18hur. + => neue Zeile mit quantity = 2, tolerance = 0, und created_on = 18uhr +* Jetzt gibt es zwei zeilen die insgesamt 4(2) ergeben. + (die summen in `GroupOrderArticle` werden aktualisiert) + +### Verringere die Mengen des Artikels. +Jetzt muss chronologisch zurueckgegangen werden und um die urspruenglich bestellten +Mengen zu verringern. + +Beispiel von oben: +* Verringe Bestellung auf 2(1) um 19uhr. + => Zeile mit created_on = 18uhr wird gelöscht und + in der Zeile mit created_on = 17uhr wird der Wert tolerance auf 1 gaendert. + +## Wer bekommt wieviel? + +Diese Frage wird wie schon erwaehnt mittels der `group_order_article_quantites`-Tabelle +geloest. + +Beispiel. + +* articel x mit unit_quantity = 5. + * 17uhr: gruppe a bestellt 2(3), weil sie auf jeden fall was von x bekommen will + * 18uhr: gruppe b bestellt 2(0) + * 19uhr: gruppe a faellt ein dass sie doch noch mehr braucht von x und aendert auf 4(1). + +* jetzt gibt es drei zeilen in der tabelle, die so aussehen: + * (gruppe a), 2(1), 17uhr (wurde um 19uhr von 2(3) auf 2(1) geaendert) + * (gruppe b), 2(0), 18uhr + * (gruppe a), 2(0), 19uhr. + +* die zuteilung wird dann wie folgt ermittelt: + * zeile 1: gruppe a bekommt 2 + * zeile 2: gruppe b bekommt 2 + * zeile 3: gruppe a bekommt 1, weil jetzt das gebinde schon voll ist. + +* Endstand: insg. Bestellt wurden 6(1) + * Gruppe a bekommt 3 einheiten. + * gruppe b bekommt 2 einheiten. + * eine Einheit verfaellt. diff --git a/doc/README_FOR_APP.md b/doc/README_FOR_APP.md deleted file mode 100644 index 0f25c510..00000000 --- a/doc/README_FOR_APP.md +++ /dev/null @@ -1,94 +0,0 @@ -Use this README file to introduce your application and point to useful places in the API for learning more. -Run "rake doc:app" to generate API documentation for your models and controllers. - -= The Foodsoft - -is a Web-based software to manage a non-profit food coop (product catalog, ordering, accounting, job scheduling). - - -== Bestellen -Das Bestellen ist der Hauptteil dieser Software und ein wenig kompliziert. -Hier starte ich den Versuch die Programmlogik in Text umzusetzen und -verweise auf die enstprechenden Controller bzw. Modelle. -Der relevante Controller ist OrderingController. - -=== Bestellung "in Netz stellen" -Darunter verstehen wir die Auswahl von Artikeln eines bestimmten Lieferanten fuer eine zeitlich begrenzte -Bestellung im Internet. Die relevanten Methoden sind OrdersController#newOrder und folgende. -Jede Bestellung wird durch die Klasse Order abgebildet. - -Die zugehoerigen Artikel werden duch die Klasse OrderArticle mit den Artikeln verknuepft. -Dabei werden auch die Attribute quantity, tolerance und quantity_to_order gespeichert. -Diese Mengen repraesentieren die Gesamtbestellung, also alle Bestellgruppen. - -=== Eine Bestellgruppe bestellt... -Die Methode OrdersController#order schickt uns die Bestellenseite. Mit dieser Oberflaeche -koennen die Bestellgruppena die vorher ausgewaehlten Artikel bestellen. -Mittels den Buttons werden dabei live, also clientseitig, die Preise ermittelt -und der Gesamtpreis berechnet. Ist der Gesamtpreis groeßer als der aktuelle -Gruppenkontostand, so wird die Preisspalte rot unterlegt und die Bestellung -kann nicht gespeichert werden. - -=== (gruppen)-Bestellung wird gespeichert - -Die Gruppenbestellung wird durch die Tabelle group_oders (GroupOrder) -abgebildet, bzw. die Bestellung und Bestellgruppe wird dort verknuepft. - -Die bestellten Artikel der Bestellgruppe werden durch die Tablle group_order_articles -(GroupOrderArticle) registriert. Dort werden nun die Modelle GroupOrder -und OrderArticle miteinander verbunden. - -Bei jeder Bestellung wird außerdem die Summe der Menge, Toleranz in GroupOrderArticle -abgelegt. Allerdings muss jede Aenderung dieser Mengen mit protokolliert werden. -Dies ist wichtig, weil spaeter die Zuteilung der Einheiten pro bestellten Artikel -nach der chronologischen Reihenfolge erfolgt. (s.u.) -Das passiert dann in der Tabelle group_order_article_quantities. -(GroupOrderArticleQuantity) - -=== Aenderunug einer Bestellung - -Knifflig ist die Aenderung einer gruppenbestellung, weil die zeitliche -Reihenfolge dabei nicht durcheinander geraten darf. -Wir unterscheiden dehalb zwei Faelle: -==== Erhoehe die Menge des Arikels. - Jetzt wird eine Zeile in group_order_article_quantities angelegt. - und zwar mit genau den Mengen, die zusatzlich bestellt wurden. - Quantity und Tolerance funktionieren analog. - Beispiel: - Urspruenglich bestellt: 2(2) um 17uhr. - Erhoehe Bestellung auf 4(2) um 18hur. - => neue Zeile mit quantity= 2, tolerance = 0, und created_on = 18uhr - Jetzt gibt es zwei zeilen die insgesamt 4(2) ergeben. - (die summen in GroupOrderArticle werden aktualisiert) -==== Verringere die Mengen des Artikels. - Jetzt muss chronologisch zurueckgegangen werden und um die urspruenglich bestellten - Mengen zu verringern. - Beispiel von oben: - Verringe Bestellung auf 2(1) um 19uhr. - => Zeile mit created_on = 18uhr wird gelöscht und - in der Zeile mit created_on = 17uhr wird der Wert tolerance auf 1 gaendert. - -=== Wer bekommt wieviel? - -Diese Frage wird wie schon erwaehnt mittels der group_order_article_quantites -Tabelle -geloest. -Beipspiel. - articel x mit unit_quantity = 5. - 17uhr: gruppe a bestellt 2(3), weil sie auf jeden fall was von x bekommen will - 18uhr: gruppe b bestellt 2(0) - 19uhr: gruppe a faellt ein dass sie doch noch mehr braucht von x und aendert auf 4(1). - - jetzt gibt es drei zeilen in der tabelle, die so aussehen: - (gruppe a), 2(1), 17uhr (wurde um 19uhr von 2(3) auf 2(1) geaendert) - (gruppe b), 2(0), 18uhr - (gruppe a), 2(0), 19uhr. - - die zuteilung wird dann wie folgt ermittelt: - zeile 1: gruppe a bekommt 2 - zeile 2: gruppe b bekommt 2 - zeile 3: gruppe a bekommt 1, weil jetzt das gebinde schon voll ist. - - Endstand: insg. Bestellt wurden 6(1) - Gruppe a bekommt 3 einheiten. - gruppe b bekommt 2 einheiten. - eine Einheit verfaellt. diff --git a/doc/SETUP_DEVELOPMENT.md b/doc/SETUP_DEVELOPMENT.md index 18a2b16f..9941c262 100644 --- a/doc/SETUP_DEVELOPMENT.md +++ b/doc/SETUP_DEVELOPMENT.md @@ -66,7 +66,7 @@ If you want to have more control, you can do these steps manually as explained here. -1. **Configure datebase** +1. **Configure database** Create the database configuration from the default: ```sh diff --git a/lib/foodsoft_wiki/README.md b/lib/foodsoft_wiki/README.md new file mode 100644 index 00000000..dcf2f18c --- /dev/null +++ b/lib/foodsoft_wiki/README.md @@ -0,0 +1,18 @@ +FoodsoftWiki +============ + +This plugin adds wiki pages to foodsoft. A new 'Wiki' menu is added next to +the 'Foodcoops' menu in the navigation bar. + +This plugin is enabled by default in foodsoft, so you don't need to do anything +to install it. If you still want to, for example when it has been disabled, +add the following to foodsoft's Gemfile: + +```Gemfile +# we use the git version of acts_as_versioned, so this needs to be in foodsoft's Gemfile +gem 'acts_as_versioned', git: 'git://github.com/technoweenie/acts_as_versioned.git' +gem 'foodsoft_wiki', path: 'lib/foodsoft_wiki' +``` + +This plugin is part of the foodsoft package and uses the GPL-3 license (see +foodsoft's LICENSE for the full license text). diff --git a/lib/foodsoft_wiki/Rakefile b/lib/foodsoft_wiki/Rakefile new file mode 100644 index 00000000..a3d12088 --- /dev/null +++ b/lib/foodsoft_wiki/Rakefile @@ -0,0 +1,40 @@ +#!/usr/bin/env rake +begin + require 'bundler/setup' +rescue LoadError + puts 'You must `gem install bundler` and `bundle install` to run rake tasks' +end +begin + require 'rdoc/task' +rescue LoadError + require 'rdoc/rdoc' + require 'rake/rdoctask' + RDoc::Task = Rake::RDocTask +end + +RDoc::Task.new(:rdoc) do |rdoc| + rdoc.rdoc_dir = 'rdoc' + rdoc.title = 'FoodsoftWiki' + rdoc.options << '--line-numbers' + rdoc.rdoc_files.include('README.rdoc') + rdoc.rdoc_files.include('lib/**/*.rb') +end + +APP_RAKEFILE = File.expand_path("../test/dummy/Rakefile", __FILE__) +load 'rails/tasks/engine.rake' + + + +Bundler::GemHelper.install_tasks + +require 'rake/testtask' + +Rake::TestTask.new(:test) do |t| + t.libs << 'lib' + t.libs << 'test' + t.pattern = 'test/**/*_test.rb' + t.verbose = false +end + + +task :default => :test diff --git a/app/controllers/pages_controller.rb b/lib/foodsoft_wiki/app/controllers/pages_controller.rb similarity index 100% rename from app/controllers/pages_controller.rb rename to lib/foodsoft_wiki/app/controllers/pages_controller.rb diff --git a/app/helpers/pages_helper.rb b/lib/foodsoft_wiki/app/helpers/pages_helper.rb similarity index 100% rename from app/helpers/pages_helper.rb rename to lib/foodsoft_wiki/app/helpers/pages_helper.rb diff --git a/app/models/page.rb b/lib/foodsoft_wiki/app/models/page.rb similarity index 100% rename from app/models/page.rb rename to lib/foodsoft_wiki/app/models/page.rb diff --git a/app/views/pages/_body.html.haml b/lib/foodsoft_wiki/app/views/pages/_body.html.haml similarity index 100% rename from app/views/pages/_body.html.haml rename to lib/foodsoft_wiki/app/views/pages/_body.html.haml diff --git a/app/views/pages/_form.html.haml b/lib/foodsoft_wiki/app/views/pages/_form.html.haml similarity index 100% rename from app/views/pages/_form.html.haml rename to lib/foodsoft_wiki/app/views/pages/_form.html.haml diff --git a/app/views/pages/_page_list_item.html.haml b/lib/foodsoft_wiki/app/views/pages/_page_list_item.html.haml similarity index 100% rename from app/views/pages/_page_list_item.html.haml rename to lib/foodsoft_wiki/app/views/pages/_page_list_item.html.haml diff --git a/app/views/pages/_recent_changes.html.haml b/lib/foodsoft_wiki/app/views/pages/_recent_changes.html.haml similarity index 100% rename from app/views/pages/_recent_changes.html.haml rename to lib/foodsoft_wiki/app/views/pages/_recent_changes.html.haml diff --git a/app/views/pages/_site_map.html.haml b/lib/foodsoft_wiki/app/views/pages/_site_map.html.haml similarity index 100% rename from app/views/pages/_site_map.html.haml rename to lib/foodsoft_wiki/app/views/pages/_site_map.html.haml diff --git a/app/views/pages/_title_list.html.haml b/lib/foodsoft_wiki/app/views/pages/_title_list.html.haml similarity index 100% rename from app/views/pages/_title_list.html.haml rename to lib/foodsoft_wiki/app/views/pages/_title_list.html.haml diff --git a/app/views/pages/all.html.haml b/lib/foodsoft_wiki/app/views/pages/all.html.haml similarity index 100% rename from app/views/pages/all.html.haml rename to lib/foodsoft_wiki/app/views/pages/all.html.haml diff --git a/app/views/pages/edit.html.haml b/lib/foodsoft_wiki/app/views/pages/edit.html.haml similarity index 100% rename from app/views/pages/edit.html.haml rename to lib/foodsoft_wiki/app/views/pages/edit.html.haml diff --git a/app/views/pages/new.html.haml b/lib/foodsoft_wiki/app/views/pages/new.html.haml similarity index 100% rename from app/views/pages/new.html.haml rename to lib/foodsoft_wiki/app/views/pages/new.html.haml diff --git a/app/views/pages/show.html.haml b/lib/foodsoft_wiki/app/views/pages/show.html.haml similarity index 100% rename from app/views/pages/show.html.haml rename to lib/foodsoft_wiki/app/views/pages/show.html.haml diff --git a/app/views/pages/version.html.haml b/lib/foodsoft_wiki/app/views/pages/version.html.haml similarity index 100% rename from app/views/pages/version.html.haml rename to lib/foodsoft_wiki/app/views/pages/version.html.haml diff --git a/lib/foodsoft_wiki/config/routes.rb b/lib/foodsoft_wiki/config/routes.rb new file mode 100644 index 00000000..29a5ebef --- /dev/null +++ b/lib/foodsoft_wiki/config/routes.rb @@ -0,0 +1,15 @@ +Rails.application.routes.draw do + + scope '/:foodcoop' do + + resources :pages do + get :all, :on => :collection + get :version, :on => :member + get :revert, :on => :member + end + match '/wiki/:permalink' => 'pages#show', :as => 'wiki_page' # , :constraints => {:permalink => /[^\s]+/} + match '/wiki' => 'pages#show', :defaults => {:permalink => 'Home'}, :as => 'wiki' + + end + +end diff --git a/db/migrate/20090325175756_create_pages.rb b/lib/foodsoft_wiki/db/migrate/20090325175756_create_pages.rb similarity index 100% rename from db/migrate/20090325175756_create_pages.rb rename to lib/foodsoft_wiki/db/migrate/20090325175756_create_pages.rb diff --git a/lib/foodsoft_wiki/foodsoft_wiki.gemspec b/lib/foodsoft_wiki/foodsoft_wiki.gemspec new file mode 100644 index 00000000..937a887f --- /dev/null +++ b/lib/foodsoft_wiki/foodsoft_wiki.gemspec @@ -0,0 +1,24 @@ +$:.push File.expand_path("../lib", __FILE__) + +# Maintain your gem's version: +require "foodsoft_wiki/version" + +# Describe your gem and declare its dependencies: +Gem::Specification.new do |s| + s.name = "foodsoft_wiki" + s.version = FoodsoftWiki::VERSION + s.authors = ["wvengen"] + s.email = ["dev-foodsoft@willem.engen.nl"] + s.homepage = "https://github.com/foodcoops/foodsoft" + s.summary = "Wiki plugin for foodsoft." + s.description = "Adds a wiki to foodsoft." + + s.files = Dir["{app,config,db,lib}/**/*"] + ["Rakefile", "README.md"] + s.test_files = Dir["test/**/*"] + + s.add_dependency "rails", "~> 3.2.15" + s.add_dependency 'wikicloth' + s.add_dependency 'acts_as_versioned' # need git version, make sure that is included in foodsoft's Gemfile + + s.add_development_dependency "sqlite3" +end diff --git a/lib/foodsoft_wiki/lib/foodsoft_wiki.rb b/lib/foodsoft_wiki/lib/foodsoft_wiki.rb new file mode 100644 index 00000000..acf5ef50 --- /dev/null +++ b/lib/foodsoft_wiki/lib/foodsoft_wiki.rb @@ -0,0 +1,6 @@ +require 'wikicloth' +require 'acts_as_versioned' +require 'foodsoft_wiki/engine' + +module FoodsoftWiki +end diff --git a/lib/foodsoft_wiki/lib/foodsoft_wiki/engine.rb b/lib/foodsoft_wiki/lib/foodsoft_wiki/engine.rb new file mode 100644 index 00000000..68f0ab7f --- /dev/null +++ b/lib/foodsoft_wiki/lib/foodsoft_wiki/engine.rb @@ -0,0 +1,14 @@ +module FoodsoftWiki + class Engine < ::Rails::Engine + def navigation(primary, ctx) + primary.item :wiki, I18n.t('navigation.wiki.title'), '#', id: nil do |subnav| + subnav.item :wiki_home, I18n.t('navigation.wiki.home'), ctx.wiki_path, id: nil + subnav.item :all_pages, I18n.t('navigation.wiki.all_pages'), ctx.all_pages_path, id: nil + end + # move this last added item to just after the foodcoop menu + if i = primary.items.index(primary[:foodcoop]) + primary.items.insert(i+1, primary.items.delete_at(-1)) + end + end + end +end diff --git a/lib/foodsoft_wiki/lib/foodsoft_wiki/version.rb b/lib/foodsoft_wiki/lib/foodsoft_wiki/version.rb new file mode 100644 index 00000000..2a67a94e --- /dev/null +++ b/lib/foodsoft_wiki/lib/foodsoft_wiki/version.rb @@ -0,0 +1,3 @@ +module FoodsoftWiki + VERSION = "0.0.1" +end diff --git a/lib/tasks/rspec.rake b/lib/tasks/rspec.rake index b6b58452..a7d67ae5 100644 --- a/lib/tasks/rspec.rake +++ b/lib/tasks/rspec.rake @@ -1,5 +1,6 @@ begin require 'rspec/core/rake_task' + task(:spec).clear RSpec::Core::RakeTask.new(:spec) task :default => :spec rescue LoadError diff --git a/spec/models/article_spec.rb b/spec/models/article_spec.rb index e3bab788..bd0d991c 100644 --- a/spec/models/article_spec.rb +++ b/spec/models/article_spec.rb @@ -52,4 +52,58 @@ describe Article do order = create :order, supplier: supplier, article_ids: [article.id] expect(article.in_open_order).to eq(order) end + + + it 'has no shared article by default' do + expect(article.shared_article).to be_nil + end + + describe 'connected to a shared database', :type => :feature do + let(:shared_supplier) { create(:supplier) } + let(:shared_article) { create :article, supplier: shared_supplier, order_number: Faker::Lorem.characters(rand(1..12)) } + let(:supplier) { create :supplier, shared_supplier_id: shared_supplier.id } + let(:article) { create :article, supplier: supplier, order_number: shared_article.order_number } + + it 'can be found in the shared database' do + expect(article.shared_article).to_not be_nil + end + + it 'can find updates' do + changed = article.shared_article_changed? + expect(changed).to_not be_false + expect(changed.length).to be > 1 + end + + it 'can be synchronised' do + # TODO move article sync from supplier to article + article # need to reference for it to exist when syncing + updated_article = supplier.sync_all[0].select{|s| s[0].id==article.id}.first[0] + article.update_attributes updated_article.attributes.reject{|k,v| k=='id' or k=='type'} + expect(article.name).to eq(shared_article.name) + # now synchronising shouldn't change anything anymore + expect(article.shared_article_changed?).to be_false + end + + it 'does not need to synchronise an imported article' do + article = SharedArticle.find(shared_article.id).build_new_article(supplier) + expect(article.shared_article_changed?).to be_false + end + + it 'adapts to foodcoop units when synchronising' do + shared_article.unit = '1kg' + shared_article.unit_quantity = 1 + shared_article.save! + article = SharedArticle.find(shared_article.id).build_new_article(supplier) + article.article_category = create :article_category + article.unit = '200g' + article.shared_updated_on -= 1 # to make update do something + article.save! + # TODO get sync functionality in article + updated_article = supplier.sync_all[0].select{|s| s[0].id==article.id}.first[0] + article.update_attributes! updated_article.attributes.reject{|k,v| k=='id' or k=='type'} + expect(article.unit).to eq '200g' + expect(article.unit_quantity).to eq 5 + expect(article.price).to be_within(1e-3).of(shared_article.price/5) + end + end end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb index adbc4248..bba0b6b7 100644 --- a/spec/spec_helper.rb +++ b/spec/spec_helper.rb @@ -29,6 +29,8 @@ RSpec.configure do |config| config.before(:each) do DatabaseCleaner.strategy = (example.metadata[:js] ? :truncation : :transaction) DatabaseCleaner.start + # maximise window so that buttons can be found on popups + example.metadata[:js] and page.driver.browser.manage.window.maximize end config.after(:each) do DatabaseCleaner.clean diff --git a/spec/support/shared_database.rb b/spec/support/shared_database.rb new file mode 100644 index 00000000..55f8f2b3 --- /dev/null +++ b/spec/support/shared_database.rb @@ -0,0 +1,29 @@ +# http://stackoverflow.com/questions/8774227 +# http://blog.plataformatec.com.br/2011/12/three-tips-to-improve-the-performance-of-your-test-suite +class ActiveRecord::Base + mattr_accessor :shared_connection + @@shared_connection = nil + + def self.connection + @@shared_connection || retrieve_connection + end +end +# Forces all threads to share the same connection. This works on +# Capybara because it starts the web server in a thread. +ActiveRecord::Base.shared_connection = ActiveRecord::Base.connection + +ActiveSupport.on_load(:after_initialize) do + # We simulate the shared database by pointing to our own database. + # This allows running tests without additional database setup. + # But take care when designing tests using the shared database. + SharedSupplier.establish_connection Rails.env + SharedArticle.establish_connection Rails.env + # hack for different structure of shared database + SharedArticle.class_eval do + alias_attribute :number, :order_number + alias_attribute :updated_on, :updated_at + def self.find_by_number(n) + find_by_order_number(n) + end + end +end diff --git a/vendor/plugins/.gitkeep b/vendor/plugins/.gitkeep deleted file mode 100644 index e69de29b..00000000