From c2c1961bd02edcf1cb91d431a44044eb2e7d2386 Mon Sep 17 00:00:00 2001 From: Manuel Wiedenmann Date: Fri, 31 May 2013 18:42:28 +0200 Subject: [PATCH 01/51] adds i18n support to routes and application controller; default_locale is set to :en --- app/controllers/application_controller.rb | 13 +- config/application.rb | 2 +- config/routes.rb | 356 +++++++++++----------- lib/foodsoft/controller_extensions.rb | 52 ++++ 4 files changed, 239 insertions(+), 184 deletions(-) create mode 100644 lib/foodsoft/controller_extensions.rb diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 29b752a0..96b2e510 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -1,10 +1,13 @@ # encoding: utf-8 class ApplicationController < ActionController::Base + include Foodsoft::ControllerExtensions::Locale + helper_method :available_locales protect_from_forgery - before_filter :select_language, :select_foodcoop, :authenticate, :store_controller, :items_per_page, :set_redirect_to + before_filter :select_foodcoop, :authenticate, :store_controller, :items_per_page, :set_redirect_to after_filter :remove_controller + # Returns the controller handling the current request. def self.current Thread.current[:application_controller] @@ -26,7 +29,7 @@ class ApplicationController < ActionController::Base redirect_to login_url, :alert => 'Access denied!' end - private + private def authenticate(role = 'any') # Attempt to retrieve authenticated user from controller instance or session... @@ -141,9 +144,5 @@ class ApplicationController < ActionController::Base def default_url_options(options = {}) {foodcoop: FoodsoftConfig.scope} end - - # Used to prevent accidently switching to :en in production mode. - def select_language - I18n.locale = :de - end + end diff --git a/config/application.rb b/config/application.rb index 32ea295b..6d519277 100644 --- a/config/application.rb +++ b/config/application.rb @@ -31,7 +31,7 @@ module Foodsoft # Internationalization. config.i18n.load_path += Dir[Rails.root.join('config', 'locales', '**', '*.{rb,yml}')] - config.i18n.default_locale = :de + config.i18n.default_locale = :en # Configure the default encoding used in templates for Ruby 1.9. config.encoding = "utf-8" diff --git a/config/routes.rb b/config/routes.rb index cbcf2828..b4e8ab4b 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -8,183 +8,187 @@ Foodsoft::Application.routes.draw do root :to => redirect("/#{FoodsoftConfig.scope}") - scope '/:foodcoop' do - - # Root path - root :to => 'home#index' - - ########### Sessions - - 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 - 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' - 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 - member do - post :finish - post :add_comment - end - end - - resources :group_orders do - get :archive, :on => :collection - end - - resources :order_comments, :only => [:new, :create] - - ############ Foodcoop orga - - resources :invites, :only => [:new, :create] - - resources :tasks do - collection do - get :user - get :archive - get :workgroup - end - member do - post :accept - post :reject - post :set_done - end - end - - resources :messages, :only => [:index, :show, :new, :create] - - namespace :foodcoop do - root :to => 'users#index' - - resources :users, :only => [:index] - - resources :ordergroups, :only => [:index] - - resources :workgroups, :only => [:index, :edit, :update] - end - - ########### Article management - - resources :stock_takings do - collection do - get :fill_new_stock_article_form - post :add_stock_article - end - end - - resources :stock_articles, :to => 'stockit' do - collection do - get :articles_search - get :fill_new_stock_article_form - end - end - - resources :suppliers do - get :shared_suppliers, :on => :collection - - resources :deliveries do - post :drop_stock_change, :on => :member - post :add_stock_article, :on => :collection - end - - resources :articles do - collection do - post :update_selected - get :edit_all - post :update_all - get :upload - post :parse_upload - post :create_from_upload - get :shared - get :import - post :sync - post :update_synchronized + constraints(locale: /[a-z]{2}/) do + scope "(:locale)" do + scope '/:foodcoop' do + + # Root path + root :to => 'home#index' + + ########### Sessions + + 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 + 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' + 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 - end - end - - resources :article_categories - - ########### Finance - - namespace :finance do - root :to => 'base#index' - - resources :order, controller: 'balancing', path: 'balancing' do - member do - get :update_summary - get :edit_note - put :update_note - - get :confirm - put :close - put :close_direct + 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 + member do + post :finish + post :add_comment + end end - - resources :order_articles - end - - resources :group_order_articles do - member do - put :update_result + + resources :group_orders do + get :archive, :on => :collection end - end - - resources :invoices - - resources :ordergroups, :only => [:index] do - resources :financial_transactions, :as => :transactions - end - - get 'transactions/new_collection' => 'financial_transactions#new_collection', :as => 'new_transaction_collection' - post 'transactions/create_collection' => 'financial_transactions#create_collection', :as => 'create_transaction_collection' - end - - ########### Administration - - namespace :admin do - root :to => 'base#index' - - resources :users - - resources :workgroups do - get :memberships, :on => :member - end - - resources :ordergroups do - get :memberships, :on => :member - end - end - - ############## Feedback - - resource :feedback, :only => [:new, :create], :controller => 'feedback' - - ############## The rest - - 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 + + resources :order_comments, :only => [:new, :create] + + ############ Foodcoop orga + + resources :invites, :only => [:new, :create] + + resources :tasks do + collection do + get :user + get :archive + get :workgroup + end + member do + post :accept + post :reject + post :set_done + end + end + + resources :messages, :only => [:index, :show, :new, :create] + + namespace :foodcoop do + root :to => 'users#index' + + resources :users, :only => [:index] + + resources :ordergroups, :only => [:index] + + resources :workgroups, :only => [:index, :edit, :update] + end + + ########### Article management + + resources :stock_takings do + collection do + get :fill_new_stock_article_form + post :add_stock_article + end + end + + resources :stock_articles, :to => 'stockit' do + collection do + get :articles_search + get :fill_new_stock_article_form + end + end + + resources :suppliers do + get :shared_suppliers, :on => :collection + + resources :deliveries do + post :drop_stock_change, :on => :member + post :add_stock_article, :on => :collection + end + + resources :articles do + collection do + post :update_selected + get :edit_all + post :update_all + get :upload + post :parse_upload + post :create_from_upload + get :shared + get :import + post :sync + post :update_synchronized + end + end + end + + resources :article_categories + + ########### Finance + + namespace :finance do + root :to => 'base#index' + + resources :order, controller: 'balancing', path: 'balancing' do + member do + get :update_summary + get :edit_note + put :update_note + + get :confirm + put :close + put :close_direct + end + + resources :order_articles + end + + resources :group_order_articles do + member do + put :update_result + end + end + + resources :invoices + + resources :ordergroups, :only => [:index] do + resources :financial_transactions, :as => :transactions + end + + get 'transactions/new_collection' => 'financial_transactions#new_collection', :as => 'new_transaction_collection' + post 'transactions/create_collection' => 'financial_transactions#create_collection', :as => 'create_transaction_collection' + end + + ########### Administration + + namespace :admin do + root :to => 'base#index' + + resources :users + + resources :workgroups do + get :memberships, :on => :member + end + + resources :ordergroups do + get :memberships, :on => :member + end + end + + ############## Feedback + + resource :feedback, :only => [:new, :create], :controller => 'feedback' + + ############## The rest + + 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 # End of /:locale scope + end # End of :locale constraints end diff --git a/lib/foodsoft/controller_extensions.rb b/lib/foodsoft/controller_extensions.rb new file mode 100644 index 00000000..fe8c940f --- /dev/null +++ b/lib/foodsoft/controller_extensions.rb @@ -0,0 +1,52 @@ +# -*- encoding : utf-8 -*- +module Foodsoft + module ControllerExtensions + module Locale + extend ActiveSupport::Concern + + included do + before_filter :set_locale + end + + module InstanceMethods + def explicitly_requested_language + params[:locale] + end + + def session_language + session[:locale] + end + + def browser_language + request.env['HTTP_ACCEPT_LANGUAGE'] ? request.env['HTTP_ACCEPT_LANGUAGE'].scan(/^[a-z]{2}/).first : nil + end + + def default_language + ::I18n.default_locale + end + + protected + + def select_language_according_to_priority + explicitly_requested_language || session_language || browser_language + end + + def available_locales + ::I18n.available_locales + end + + def set_locale + if available_locales.include?(select_language_according_to_priority) + ::I18n.locale = select_language_according_to_priority + else + ::I18n.locale = default_language + end + + locale = session[:locale] = ::I18n.locale + logger.info("Set locale to #{locale}") + end + end + + end + end +end \ No newline at end of file From 47405b5b19364ea166db1eea9fe90ed6210d1177 Mon Sep 17 00:00:00 2001 From: Manuel Wiedenmann Date: Thu, 6 Jun 2013 03:18:02 +0200 Subject: [PATCH 02/51] fixes locales issue --- lib/foodsoft/controller_extensions.rb | 57 +++++++++++++-------------- 1 file changed, 28 insertions(+), 29 deletions(-) diff --git a/lib/foodsoft/controller_extensions.rb b/lib/foodsoft/controller_extensions.rb index fe8c940f..ea8c5265 100644 --- a/lib/foodsoft/controller_extensions.rb +++ b/lib/foodsoft/controller_extensions.rb @@ -8,43 +8,42 @@ module Foodsoft before_filter :set_locale end - module InstanceMethods - def explicitly_requested_language - params[:locale] - end + def explicitly_requested_language + params[:locale] + end - def session_language - session[:locale] - end + def session_language + session[:locale] + end - def browser_language - request.env['HTTP_ACCEPT_LANGUAGE'] ? request.env['HTTP_ACCEPT_LANGUAGE'].scan(/^[a-z]{2}/).first : nil - end + def browser_language + request.env['HTTP_ACCEPT_LANGUAGE'] ? request.env['HTTP_ACCEPT_LANGUAGE'].scan(/^[a-z]{2}/).first : nil + end - def default_language - ::I18n.default_locale - end + def default_language + ::I18n.default_locale + end - protected + protected - def select_language_according_to_priority - explicitly_requested_language || session_language || browser_language - end + def select_language_according_to_priority + language = explicitly_requested_language || session_language || browser_language + language.to_sym unless language.blank? + end - def available_locales - ::I18n.available_locales - end + def available_locales + ::I18n.available_locales + end - def set_locale - if available_locales.include?(select_language_according_to_priority) - ::I18n.locale = select_language_according_to_priority - else - ::I18n.locale = default_language - end - - locale = session[:locale] = ::I18n.locale - logger.info("Set locale to #{locale}") + def set_locale + if available_locales.include?(select_language_according_to_priority) + ::I18n.locale = select_language_according_to_priority + else + ::I18n.locale = default_language end + + locale = session[:locale] = ::I18n.locale + logger.info("Set locale to #{locale}") end end From e8173d44aee250a99be06e9ab5189ad16e7587e1 Mon Sep 17 00:00:00 2001 From: Manuel Wiedenmann Date: Thu, 6 Jun 2013 03:21:44 +0200 Subject: [PATCH 03/51] adds rails-settings cached and rails-i18n-debug gems --- Gemfile | 9 +++++++-- Gemfile.lock | 9 ++++++--- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/Gemfile b/Gemfile index e794d5a8..4de14f07 100644 --- a/Gemfile +++ b/Gemfile @@ -35,7 +35,7 @@ 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 'acts_as_configurable', git: 'git://github.com/bwalding/acts_as_configurable.git' +gem "rails-settings-cached", "0.2.4" gem 'resque' gem 'whenever', require: false # For defining cronjobs, see config/schedule.rb @@ -50,7 +50,8 @@ group :development do # Better error output gem 'better_errors' gem 'binding_of_caller' - + # gem "rails-i18n-debug" + # Re-enable rails benchmarker/profiler gem 'ruby-prof' gem 'test-unit' @@ -66,3 +67,7 @@ group :development do gem 'capistrano-ext' gem 'common_deploy', require: false, path: '../../common_deploy' #git: 'git://github.com/fsmanuel/common_deploy.git' end + +# Gems left for backwards compatibility +gem 'acts_as_configurable', git: 'git://github.com/bwalding/acts_as_configurable.git' # user settings migration needs it + diff --git a/Gemfile.lock b/Gemfile.lock index 447cb723..173c8c7a 100644 --- a/Gemfile.lock +++ b/Gemfile.lock @@ -108,7 +108,7 @@ GEM has_scope (0.5.1) hashery (2.0.1) highline (1.6.19) - hike (1.2.1) + hike (1.2.3) i18n (0.6.1) inherited_resources (1.3.1) has_scope (~> 0.5.0) @@ -147,7 +147,7 @@ GEM polyamorous (~> 0.5.0) mime-types (1.21) mono_logger (1.1.0) - multi_json (1.7.3) + multi_json (1.7.6) mysql2 (0.3.11) net-scp (1.1.1) net-ssh (>= 2.6.5) @@ -185,6 +185,8 @@ GEM activesupport (= 3.2.13) bundler (~> 1.0) railties (= 3.2.13) + rails-settings-cached (0.2.4) + rails (>= 3.0.0) railties (3.2.13) actionpack (= 3.2.13) activesupport (= 3.2.13) @@ -225,7 +227,7 @@ GEM activesupport (>= 2.3.2) simple-navigation-bootstrap (0.0.4) simple-navigation (>= 3.7.0) - simple_form (2.0.3) + simple_form (2.1.0) actionpack (~> 3.0) activemodel (~> 3.0) sinatra (1.3.6) @@ -301,6 +303,7 @@ DEPENDENCIES prawn quiet_assets rails (~> 3.2.9) + rails-settings-cached (= 0.2.4) resque ruby-prof sass-rails (~> 3.2.3) From 60c4c5510a389b7c371e66a68fd0a27e2cb393cf Mon Sep 17 00:00:00 2001 From: Manuel Wiedenmann Date: Thu, 6 Jun 2013 03:40:15 +0200 Subject: [PATCH 04/51] adds a new user settings system + migration + rake task/worker updates --- app/models/user.rb | 61 +++++++------------ app/views/shared/_user_form_fields.html.haml | 24 +++++--- app/workers/user_notifier.rb | 4 +- config/locales/de/de.defaults.yml | 8 --- config/locales/de/de.simple_form.yml | 18 ++++++ config/locales/en/en.defaults.yml | 8 --- config/locales/en/en.simple_form.yml | 18 ++++++ db/migrate/20130605112109_create_settings.rb | 17 ++++++ .../20130605235825_migrate_user_settings.rb | 34 +++++++++++ db/schema.rb | 13 +++- lib/tasks/foodsoft.rake | 4 +- 11 files changed, 141 insertions(+), 68 deletions(-) create mode 100644 db/migrate/20130605112109_create_settings.rb create mode 100644 db/migrate/20130605235825_migrate_user_settings.rb diff --git a/app/models/user.rb b/app/models/user.rb index 359bf51c..1b0e818a 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -3,6 +3,7 @@ require 'digest/sha1' # specific user rights through memberships (see Group) class User < ActiveRecord::Base + include RailsSettings::Extend #TODO: acts_as_paraniod ?? has_many :memberships, :dependent => :destroy @@ -19,8 +20,11 @@ class User < ActiveRecord::Base 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, :setting_attributes - + attr_accessor :password, :settings_attributes + + # makes the current_user (logged-in-user) available in models + cattr_accessor :current_user + validates_presence_of :nick, :email validates_presence_of :password, :on => :create validates_length_of :nick, :in => 2..25 @@ -32,44 +36,23 @@ class User < ActiveRecord::Base validates_length_of :password, :in => 5..25, :allow_blank => true before_validation :set_password - after_save :update_settings - - # Adds support for configuration settings (through "settings" attribute). - acts_as_configurable - - # makes the current_user (logged-in-user) available in models - cattr_accessor :current_user - - # User settings keys - # returns the User-settings and the translated description - def self.setting_keys - { - "notify.orderFinished" => I18n.t('model.user.notify.order_finished'), - "notify.negativeBalance" => I18n.t('model.user.notify.negative_balance'), - "notify.upcoming_tasks" => I18n.t('model.user.notify.upcoming_tasks'), - "messages.sendAsEmail" => I18n.t('model.user.notify.send_as_email'), - "profile.phoneIsPublic" => I18n.t('model.user.notify.phone_is_public'), - "profile.emailIsPublic" => I18n.t('model.user.notify.email_is_public'), - "profile.nameIsPublic" => I18n.t('model.user.notify.name_is_public') - } + after_initialize do + settings.defaults['profile'] = { 'language' => I18n.default_locale } unless settings.profile + settings.defaults['messages'] = { 'send_as_email' => true } unless settings.messages + settings.defaults['notify'] = { 'upcoming_tasks' => true } unless settings.notify end - # retuns the default setting for a NEW user - # for old records nil will returned - # TODO: integrate default behaviour in acts_as_configurable plugin - def settings_default(setting) - # define a default for the settings - defaults = { - "messages.sendAsEmail" => true, - "notify.upcoming_tasks" => true - } - return true if self.new_record? && defaults[setting] - end - - def update_settings - unless setting_attributes.nil? - for setting in User::setting_keys.keys - self.settings[setting] = setting_attributes[setting] && setting_attributes[setting] == '1' ? '1' : nil + + after_save do + settings_attributes.each do |key, value| + value.each do |k, v| + case v + when '1' + value[k] = true + when '0' + value[k] = false + end end + self.settings.merge!(key, value) end end @@ -78,7 +61,7 @@ class User < ActiveRecord::Base end def receive_email? - settings['messages.sendAsEmail'] == "1" && email.present? + settings['messages.send_as_mail'] == "1" && email.present? end # Sets the user's password. It will be stored encrypted along with a random salt. diff --git a/app/views/shared/_user_form_fields.html.haml b/app/views/shared/_user_form_fields.html.haml index fa11b393..21d5fe2b 100644 --- a/app/views/shared/_user_form_fields.html.haml +++ b/app/views/shared/_user_form_fields.html.haml @@ -5,11 +5,19 @@ = f.input :phone = f.input :password, :required => f.object.new_record? = f.input :password_confirmation -.control-group - .controls - - for setting in User::setting_keys.keys - %label.checkbox{:for => "user[setting_attributes][#{setting}]"} - = hidden_field_tag "user[setting_attributes][#{setting}]", '0' - = check_box_tag "user[setting_attributes][#{setting}]", '1', - f.object.settings[setting] == '1' || f.object.settings_default(setting) - = User::setting_keys[setting] + += f.simple_fields_for :settings_attributes do |s| + + = s.simple_fields_for :profile, defaults: { inline_label: true } do |profile| + = profile.input 'language', as: :select, collection: available_locales, required: false, selected: f.object.settings.profile['language'] + = profile.input 'phone_is_public', as: :boolean, label: false, input_html: { checked: f.object.settings.profile['phone_is_public'] } + = profile.input 'email_is_public', as: :boolean, label: false, input_html: { checked: f.object.settings.profile['email_is_public'] } + = profile.input 'name_is_public', as: :boolean, label: false, input_html: { checked: f.object.settings.profile['name_is_public'] } + + = s.simple_fields_for :messages, defaults: { inline_label: true, label: false } do |messages| + = messages.input 'send_as_email', as: :boolean, input_html: { checked: f.object.settings.messages['send_as_email'] } + + = s.simple_fields_for :notify, defaults: { inline_label: true, label: false } do |notify| + = notify.input 'order_finished', as: :boolean, input_html: { checked: f.object.settings.notify['order_finished'] } + = notify.input 'negative_balance', as: :boolean, input_html: { checked: f.object.settings.notify['negative_balance'] } + = notify.input 'upcoming_tasks', as: :boolean, input_html: { checked: f.object.settings.notify['upcoming_tasks'] } diff --git a/app/workers/user_notifier.rb b/app/workers/user_notifier.rb index 297ae978..754477d5 100644 --- a/app/workers/user_notifier.rb +++ b/app/workers/user_notifier.rb @@ -18,7 +18,7 @@ class UserNotifier Order.find(order_id).group_orders.each do |group_order| group_order.ordergroup.users.each do |user| begin - Mailer.order_result(user, group_order).deliver if user.settings["notify.orderFinished"] == '1' + Mailer.order_result(user, group_order).deliver if user.settings.notify["order_finished"] rescue Rails.logger.warn "Can't deliver mail to #{user.email}" end @@ -34,7 +34,7 @@ class UserNotifier Ordergroup.find(ordergroup_id).users.each do |user| begin - Mailer.negative_balance(user, transaction).deliver if user.settings["notify.negativeBalance"] == '1' + Mailer.negative_balance(user, transaction).deliver if user.settings.notify["negative_balance"] rescue Rails.logger.warn "Can't deliver mail to #{user.email}" end diff --git a/config/locales/de/de.defaults.yml b/config/locales/de/de.defaults.yml index 890ee796..ee8633a6 100644 --- a/config/locales/de/de.defaults.yml +++ b/config/locales/de/de.defaults.yml @@ -263,14 +263,6 @@ de: page: redirect: 'Weiterleiting auf [[%{title}]]...' user: - notify: - order_finished: 'Informier mich über meine Bestellergebnisse (nach Ende der Bestellung).' - negative_balance: 'Informiere mich, falls meine Bestellgruppe ins Minus rutscht.' - upcoming_tasks: 'Erinnere mich an anstehende Aufgaben.' - send_as_email: 'Bekomme Nachrichten als Emails.' - phone_is_public: 'Telefon ist für Mitglieder sichtbar' - email_is_public: 'E-Mail ist für Mitglieder sichtbar' - name_is_public: 'Name ist für Mitglieder sichtbar' no_ordergroup: 'keine Bestellgruppe' helpers: diff --git a/config/locales/de/de.simple_form.yml b/config/locales/de/de.simple_form.yml index 5aa5279a..db4a7610 100644 --- a/config/locales/de/de.simple_form.yml +++ b/config/locales/de/de.simple_form.yml @@ -8,6 +8,12 @@ de: mark: '*' error_notification: default_message: "Fehler wurden gefunden. Bitte das Formular überprüfen." + options: + settings: + profile: + language: + de: Deutsch + en: English labels: defaults: password: 'Passwort' @@ -30,6 +36,18 @@ de: nick: "Benutzerinnenname" first_name: "Vorname" last_name: "Nachname" + settings: + profile: + language: Sprache + phone_is_public: 'Telefon ist für Mitglieder sichtbar' + email_is_public: 'E-Mail ist für Mitglieder sichtbar' + name_is_public: 'Name ist für Mitglieder sichtbar' + notify: + order_finished: 'Informier mich über meine Bestellergebnisse (nach Ende der Bestellung).' + negative_balance: 'Informiere mich, falls meine Bestellgruppe ins Minus rutscht.' + upcoming_tasks: 'Erinnere mich an anstehende Aufgaben.' + messages: + send_as_email: 'Bekomme Nachrichten als Emails.' workgroup: weekly_task: 'Monatlichen Job definieren?' weekday: 'Wochentag' diff --git a/config/locales/en/en.defaults.yml b/config/locales/en/en.defaults.yml index ca4b436c..03a1f0e0 100644 --- a/config/locales/en/en.defaults.yml +++ b/config/locales/en/en.defaults.yml @@ -263,14 +263,6 @@ en: page: redirect: 'Redirect to [[%{title}]]...' user: - notify: - order_finished: 'Inform me about my order result (when the order is closed).' - negative_balance: 'inform me when by order group has a negative balance.' - upcoming_tasks: 'Remind me of upcoming tasks.' - send_as_email: 'Receive messages as emails.' - phone_is_public: 'Phone number is visible for other members.' - email_is_public: 'Email is visible for other members.' - name_is_public: 'Name is visible for other members.' no_ordergroup: 'no order group' helpers: diff --git a/config/locales/en/en.simple_form.yml b/config/locales/en/en.simple_form.yml index 31cc4b6c..305dde1e 100644 --- a/config/locales/en/en.simple_form.yml +++ b/config/locales/en/en.simple_form.yml @@ -8,6 +8,12 @@ en: mark: '*' error_notification: default_message: 'Errors were found. Please check the form.' + options: + settings: + profile: + language: + de: German + en: English labels: defaults: password: 'Password' @@ -30,6 +36,18 @@ en: nick: 'Username' first_name: 'First name' last_name: 'Last name' + settings: + profile: + language: Language + phone_is_public: 'Phone number is visible for other members.' + email_is_public: 'Email is visible for other members.' + name_is_public: 'Name is visible for other members.' + notify: + order_finished: 'Inform me about my order result (when the order is closed).' + negative_balance: 'inform me when by order group has a negative balance.' + upcoming_tasks: 'Remind me of upcoming tasks.' + messages: + send_as_email: 'Receive messages as emails.' workgroup: weekly_task: 'Define monthly task?' weekday: 'Weekday' diff --git a/db/migrate/20130605112109_create_settings.rb b/db/migrate/20130605112109_create_settings.rb new file mode 100644 index 00000000..90a0f527 --- /dev/null +++ b/db/migrate/20130605112109_create_settings.rb @@ -0,0 +1,17 @@ +class CreateSettings < ActiveRecord::Migration + def self.up + create_table :settings do |t| + t.string :var, null: false + t.text :value, null: true + t.integer :thing_id, null: true + t.string :thing_type, limit: 30, null: true + t.timestamps + end + + add_index :settings, [ :thing_type, :thing_id, :var ], unique: true + end + + def self.down + drop_table :settings + end +end diff --git a/db/migrate/20130605235825_migrate_user_settings.rb b/db/migrate/20130605235825_migrate_user_settings.rb new file mode 100644 index 00000000..a9722f1b --- /dev/null +++ b/db/migrate/20130605235825_migrate_user_settings.rb @@ -0,0 +1,34 @@ +class MigrateUserSettings < ActiveRecord::Migration + def up + old_settings = ConfigurableSetting.all + + old_settings.each do |old_setting| + # get target (user) + type = old_setting.configurable_type + id = old_setting.configurable_id + user = type.constantize.find(id) + + # get the data (settings) + name = old_setting.name + namespace = name.split('.')[0] + key = name.split('.')[1].underscore # Camelcase to underscore + + # prepare value + value = YAML.load(old_setting.value) + value = value.nil? ? false : value + + # set the settings_attributes (thanks to settings.merge! we can set them one by one) + user.settings_attributes = { + "#{namespace}" => { + "#{key}" => value + } + } + + # save the user to apply after_save callback + user.save + end + end + + def down + end +end diff --git a/db/schema.rb b/db/schema.rb index 188ea83b..477ebbf5 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -11,7 +11,7 @@ # # It's strongly recommended to check this file into your version control system. -ActiveRecord::Schema.define(:version => 20121230142516) do +ActiveRecord::Schema.define(:version => 20130605235825) do create_table "article_categories", :force => true do |t| t.string "name", :default => "", :null => false @@ -268,6 +268,17 @@ ActiveRecord::Schema.define(:version => 20121230142516) do add_index "pages", ["permalink"], :name => "index_pages_on_permalink" add_index "pages", ["title"], :name => "index_pages_on_title" + create_table "settings", :force => true do |t| + t.string "var", :null => false + t.text "value" + t.integer "thing_id" + t.string "thing_type", :limit => 30 + t.datetime "created_at", :null => false + t.datetime "updated_at", :null => false + end + + add_index "settings", ["thing_type", "thing_id", "var"], :name => "index_settings_on_thing_type_and_thing_id_and_var", :unique => true + create_table "stock_changes", :force => true do |t| t.integer "delivery_id" t.integer "order_id" diff --git a/lib/tasks/foodsoft.rake b/lib/tasks/foodsoft.rake index fd96cf9c..5fa4cc2a 100644 --- a/lib/tasks/foodsoft.rake +++ b/lib/tasks/foodsoft.rake @@ -8,7 +8,7 @@ namespace :foodsoft do puts "Send notifications for #{task.name} to .." for user in task.users begin - Mailer.upcoming_tasks(user, task).deliver if user.settings['notify.upcoming_tasks'] == 1 + Mailer.upcoming_tasks(user, task).deliver if user.settings.notify['upcoming_tasks'] == 1 rescue puts "deliver aborted for #{user.email}.." end @@ -38,7 +38,7 @@ namespace :foodsoft do unless task.enough_users_assigned? puts "Notify workgroup: #{workgroup.name} for task #{task.name}" for user in workgroup.users - if user.settings['messages.sendAsEmail'] == "1" && !user.email.blank? + if user.settings.messages['send_as_email'] == "1" && !user.email.blank? begin Mailer.not_enough_users_assigned(task, user).deliver rescue From 0061e45198b7df45aa67b3c967d2b37313ef2f30 Mon Sep 17 00:00:00 2001 From: Manuel Wiedenmann Date: Thu, 6 Jun 2013 04:29:53 +0200 Subject: [PATCH 05/51] removes routes locale constrain and fixes some bugs --- app/models/user.rb | 1 + app/views/admin/users/show.html.haml | 6 +- app/views/foodcoop/users/_users.html.haml | 6 +- config/routes.rb | 357 +++++++++++----------- lib/foodsoft/controller_extensions.rb | 2 +- 5 files changed, 185 insertions(+), 187 deletions(-) diff --git a/app/models/user.rb b/app/models/user.rb index 1b0e818a..0a5767b6 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -43,6 +43,7 @@ class User < ActiveRecord::Base end after_save do + return if settings_attributes.nil? settings_attributes.each do |key, value| value.each do |k, v| case v diff --git a/app/views/admin/users/show.html.haml b/app/views/admin/users/show.html.haml index a954b7d5..4d0cd1ab 100644 --- a/app/views/admin/users/show.html.haml +++ b/app/views/admin/users/show.html.haml @@ -20,10 +20,10 @@ .well %h4= t '.preference' %table.table - - for setting in User::setting_keys.keys + - @user.settings.profile.each do |key, setting| %tr - %td= User::setting_keys[setting] - %td= @user.settings[setting] == '1' ? t('simple_form.yes') : t('simple_form.no') + %td= t("simple_form.labels.settings.profile.#{key}") + %td= (setting != true and setting != false) ? setting : (setting === true ? t('simple_form.yes') : t('simple_form.no')) .span3 .well %h4= t '.groupabos' diff --git a/app/views/foodcoop/users/_users.html.haml b/app/views/foodcoop/users/_users.html.haml index 487f15e4..90b1de3a 100644 --- a/app/views/foodcoop/users/_users.html.haml +++ b/app/views/foodcoop/users/_users.html.haml @@ -14,9 +14,9 @@ - for user in @users %tr %td= user.nick - %td= user.name if @current_user.role_admin? || user.settings["profile.nameIsPublic"] == '1' - %td= user.email if @current_user.role_admin? || user.settings["profile.emailIsPublic"] == '1' - %td= user.phone if @current_user.role_admin? || user.settings["profile.phoneIsPublic"] == '1' + %td= user.name if @current_user.role_admin? || user.settings.profile["name_is_public"] + %td= user.email if @current_user.role_admin? || user.settings.profile["email_is_public"] + %td= user.phone if @current_user.role_admin? || user.settings.profile["phone_is_public"] %td= user.ordergroup_name %td= user.workgroups.collect(&:name).join(', ') %td= link_to_new_message(message_params: {mail_to: user.id}) diff --git a/config/routes.rb b/config/routes.rb index b4e8ab4b..ee60ac0a 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -8,187 +8,184 @@ Foodsoft::Application.routes.draw do root :to => redirect("/#{FoodsoftConfig.scope}") - constraints(locale: /[a-z]{2}/) do - scope "(:locale)" do - scope '/:foodcoop' do - - # Root path - root :to => 'home#index' - - ########### Sessions - - 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 - 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' - 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 + + scope '/:foodcoop' do + + # Root path + root :to => 'home#index' + + ########### Sessions + + 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 + 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' + 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 + member do + post :finish + post :add_comment + end + end + + resources :group_orders do + get :archive, :on => :collection + end + + resources :order_comments, :only => [:new, :create] + + ############ Foodcoop orga + + resources :invites, :only => [:new, :create] + + resources :tasks do + collection do + get :user + get :archive + get :workgroup + end + member do + post :accept + post :reject + post :set_done + end + end + + resources :messages, :only => [:index, :show, :new, :create] + + namespace :foodcoop do + root :to => 'users#index' + + resources :users, :only => [:index] + + resources :ordergroups, :only => [:index] + + resources :workgroups, :only => [:index, :edit, :update] + end + + ########### Article management + + resources :stock_takings do + collection do + get :fill_new_stock_article_form + post :add_stock_article + end + end + + resources :stock_articles, :to => 'stockit' do + collection do + get :articles_search + get :fill_new_stock_article_form + end + end + + resources :suppliers do + get :shared_suppliers, :on => :collection + + resources :deliveries do + post :drop_stock_change, :on => :member + post :add_stock_article, :on => :collection + end + + resources :articles do + collection do + post :update_selected + get :edit_all + post :update_all + get :upload + post :parse_upload + post :create_from_upload + get :shared + get :import + post :sync + post :update_synchronized 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 - member do - post :finish - post :add_comment - end + end + end + + resources :article_categories + + ########### Finance + + namespace :finance do + root :to => 'base#index' + + resources :order, controller: 'balancing', path: 'balancing' do + member do + get :update_summary + get :edit_note + put :update_note + + get :confirm + put :close + put :close_direct end - - resources :group_orders do - get :archive, :on => :collection + + resources :order_articles + end + + resources :group_order_articles do + member do + put :update_result end - - resources :order_comments, :only => [:new, :create] - - ############ Foodcoop orga - - resources :invites, :only => [:new, :create] - - resources :tasks do - collection do - get :user - get :archive - get :workgroup - end - member do - post :accept - post :reject - post :set_done - end - end - - resources :messages, :only => [:index, :show, :new, :create] - - namespace :foodcoop do - root :to => 'users#index' - - resources :users, :only => [:index] - - resources :ordergroups, :only => [:index] - - resources :workgroups, :only => [:index, :edit, :update] - end - - ########### Article management - - resources :stock_takings do - collection do - get :fill_new_stock_article_form - post :add_stock_article - end - end - - resources :stock_articles, :to => 'stockit' do - collection do - get :articles_search - get :fill_new_stock_article_form - end - end - - resources :suppliers do - get :shared_suppliers, :on => :collection - - resources :deliveries do - post :drop_stock_change, :on => :member - post :add_stock_article, :on => :collection - end - - resources :articles do - collection do - post :update_selected - get :edit_all - post :update_all - get :upload - post :parse_upload - post :create_from_upload - get :shared - get :import - post :sync - post :update_synchronized - end - end - end - - resources :article_categories - - ########### Finance - - namespace :finance do - root :to => 'base#index' - - resources :order, controller: 'balancing', path: 'balancing' do - member do - get :update_summary - get :edit_note - put :update_note - - get :confirm - put :close - put :close_direct - end - - resources :order_articles - end - - resources :group_order_articles do - member do - put :update_result - end - end - - resources :invoices - - resources :ordergroups, :only => [:index] do - resources :financial_transactions, :as => :transactions - end - - get 'transactions/new_collection' => 'financial_transactions#new_collection', :as => 'new_transaction_collection' - post 'transactions/create_collection' => 'financial_transactions#create_collection', :as => 'create_transaction_collection' - end - - ########### Administration - - namespace :admin do - root :to => 'base#index' - - resources :users - - resources :workgroups do - get :memberships, :on => :member - end - - resources :ordergroups do - get :memberships, :on => :member - end - end - - ############## Feedback - - resource :feedback, :only => [:new, :create], :controller => 'feedback' - - ############## The rest - - 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 # End of /:locale scope - end # End of :locale constraints + end + + resources :invoices + + resources :ordergroups, :only => [:index] do + resources :financial_transactions, :as => :transactions + end + + get 'transactions/new_collection' => 'financial_transactions#new_collection', :as => 'new_transaction_collection' + post 'transactions/create_collection' => 'financial_transactions#create_collection', :as => 'create_transaction_collection' + end + + ########### Administration + + namespace :admin do + root :to => 'base#index' + + resources :users + + resources :workgroups do + get :memberships, :on => :member + end + + resources :ordergroups do + get :memberships, :on => :member + end + end + + ############## Feedback + + resource :feedback, :only => [:new, :create], :controller => 'feedback' + + ############## The rest + + 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/lib/foodsoft/controller_extensions.rb b/lib/foodsoft/controller_extensions.rb index ea8c5265..476906cc 100644 --- a/lib/foodsoft/controller_extensions.rb +++ b/lib/foodsoft/controller_extensions.rb @@ -41,7 +41,7 @@ module Foodsoft else ::I18n.locale = default_language end - + locale = session[:locale] = ::I18n.locale logger.info("Set locale to #{locale}") end From c8c810a0a4511be30b33ae3d3096211817db11a3 Mon Sep 17 00:00:00 2001 From: Manuel Wiedenmann Date: Fri, 7 Jun 2013 19:05:28 +0200 Subject: [PATCH 06/51] added user setting to set_locale --- lib/foodsoft/controller_extensions.rb | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/foodsoft/controller_extensions.rb b/lib/foodsoft/controller_extensions.rb index 476906cc..a5f3fe6f 100644 --- a/lib/foodsoft/controller_extensions.rb +++ b/lib/foodsoft/controller_extensions.rb @@ -12,6 +12,10 @@ module Foodsoft params[:locale] end + def user_settings_language + current_user.settings.profile['language'] if current_user + end + def session_language session[:locale] end @@ -27,7 +31,7 @@ module Foodsoft protected def select_language_according_to_priority - language = explicitly_requested_language || session_language || browser_language + language = explicitly_requested_language || session_language || user_settings_language || browser_language language.to_sym unless language.blank? end From e28f3eda651418df94eadd949b32e0bd2f110f46 Mon Sep 17 00:00:00 2001 From: Julius Date: Tue, 11 Jun 2013 13:10:18 +0200 Subject: [PATCH 07/51] Fix StockArticle creation during delivery; small cleanups --- app/controllers/deliveries_controller.rb | 37 ++++++++++++------- app/views/deliveries/_form.html.haml | 20 +++------- .../deliveries/_stock_article_form.html.haml | 28 +++++++++----- app/views/deliveries/_stock_change.html.haml | 2 +- .../deliveries/add_stock_article.js.haml | 3 ++ .../deliveries/new_stock_article.js.haml | 2 + app/views/shared/_alert_success.haml | 5 +++ app/views/stockit/destroy.js.haml | 6 --- config/locales/de.yml | 6 +++ config/routes.rb | 1 + 10 files changed, 66 insertions(+), 44 deletions(-) create mode 100644 app/views/deliveries/add_stock_article.js.haml create mode 100644 app/views/deliveries/new_stock_article.js.haml create mode 100644 app/views/shared/_alert_success.haml diff --git a/app/controllers/deliveries_controller.rb b/app/controllers/deliveries_controller.rb index d8876c16..af247462 100644 --- a/app/controllers/deliveries_controller.rb +++ b/app/controllers/deliveries_controller.rb @@ -75,21 +75,32 @@ class DeliveriesController < ApplicationController end end - def add_stock_article - article = @supplier.stock_articles.build(params[:stock_article]) - render :update do |page| - if article.save - logger.debug "new StockArticle: #{article.id}" - page.insert_html :bottom, 'stock_changes', :partial => 'stock_change', - :locals => {:stock_change => article.stock_changes.build, :supplier => @supplier} + def new_stock_article + @stock_article = @supplier.stock_articles.build + render :layout => false + end - page.replace_html 'new_stock_article', :partial => 'stock_article_form', - :locals => {:stock_article => @supplier.stock_articles.build} - else - page.replace_html 'new_stock_article', :partial => 'stock_article_form', - :locals => {:stock_article => article} - end + def add_stock_article + @stock_article = StockArticle.new(params[:stock_article]) + if @stock_article.valid? and @stock_article.save + render :layout => false + else + render :action => 'new_stock_article', :layout => false end + + #render :update do |page| + # if article.save + # logger.debug "new StockArticle: #{article.id}" + # page.insert_html :bottom, 'stock_changes', :partial => 'stock_change', + # :locals => {:stock_change => article.stock_changes.build, :supplier => @supplier} +# + # page.replace_html 'new_stock_article', :partial => 'stock_article_form', + # :locals => {:stock_article => @supplier.stock_articles.build} + # else + # page.replace_html 'new_stock_article', :partial => 'stock_article_form', + # :locals => {:stock_article => article} + # end + #end end def add_stock_change diff --git a/app/views/deliveries/_form.html.haml b/app/views/deliveries/_form.html.haml index 5eff702d..bfa90114 100644 --- a/app/views/deliveries/_form.html.haml +++ b/app/views/deliveries/_form.html.haml @@ -12,6 +12,11 @@ }) }); +.well.well-small + .btn-toolbar + .btn-group + = link_to t('.new_stock_article'), new_stock_article_supplier_deliveries_path(@supplier), remote: true, class: 'btn btn-primary' + = simple_form_for [@supplier, @delivery], validate: true do |f| = f.hidden_field :supplier_id #stock_changes @@ -23,23 +28,10 @@ = stock_change_form.hidden_field :_destroy = link_to t('.remove_article'), "#", class: 'destroy_stock_change' %p - = link_to t('.add_article'), {action: 'add_stock_change', supplier_id: @supplier.id}, remote: true - %p - %small= t('.note_new_article', new_link: link_to(t('.note_new_article_link'), new_stock_article_path)).html_safe + = link_to t('.add_article'), {action: 'add_stock_change', supplier_id: @supplier.id}, remote: true, class: 'btn btn-small' %hr/ = f.input :delivered_on, as: :date_picker = f.input :note, input_html: {size: '35x4'} .form-actions = f.submit class: 'btn btn-primary' = link_to t('ui.or_cancel'), supplier_deliveries_path(@supplier) - -/ - TODO: Fix this!! - .span6 - %h2= t '.new_article.title' - %p - = t('.new_article.search', supplier: @supplier.name).html_safe + ': ' - = text_field_tag 'article_name' - %hr/ - #stock_article_form - = render 'stock_article_form', stock_article: @supplier.stock_articles.build diff --git a/app/views/deliveries/_stock_article_form.html.haml b/app/views/deliveries/_stock_article_form.html.haml index 395be839..8384eefe 100644 --- a/app/views/deliveries/_stock_article_form.html.haml +++ b/app/views/deliveries/_stock_article_form.html.haml @@ -1,11 +1,19 @@ -= simple_form_for stock_article, url: add_stock_article_supplier_deliveries_path(@supplier), remote: true, - validate: true do |f| += simple_form_for stock_article, url: add_stock_article_supplier_deliveries_path(supplier), remote: true, validate: true do |f| = f.hidden_field :supplier_id - = f.input :name - = f.input :unit - = f.input :note - = f.input :price - = f.input :tax - = f.input :deposit - = f.association :article_category - = f.submit class: 'btn' \ No newline at end of file + .modal-header + = link_to t('ui.marks.close').html_safe, '#', class: 'close', data: {dismiss: 'modal'} + %h3= t '.title' + .modal-body + = f.input :name + = f.input :unit + = f.input :note + - if stock_article.new_record? + = f.input :price + = f.input :tax + = f.input :deposit + - else + = f.input :price, :input_html => {:disabled => 'disabled'}, :hint => t('.form.price_hint') + = f.association :article_category + .modal-footer + = link_to t('ui.close'), '#', class: 'btn', data: {dismiss: 'modal'} + = f.submit class: 'btn btn-primary' diff --git a/app/views/deliveries/_stock_change.html.haml b/app/views/deliveries/_stock_change.html.haml index 3c5dfd5a..97151ecc 100644 --- a/app/views/deliveries/_stock_change.html.haml +++ b/app/views/deliveries/_stock_change.html.haml @@ -3,4 +3,4 @@ = form.select :stock_article_id, stock_articles_for_select(supplier) Menge = form.text_field :quantity, :size => 5, :autocomplete => 'off' - = link_to t('.remove_article'), "#", :class => 'remove_new_stock_change' + = link_to t('.remove_article'), "#", :class => 'remove_new_stock_change btn btn-small' diff --git a/app/views/deliveries/add_stock_article.js.haml b/app/views/deliveries/add_stock_article.js.haml new file mode 100644 index 00000000..9155f970 --- /dev/null +++ b/app/views/deliveries/add_stock_article.js.haml @@ -0,0 +1,3 @@ +$('div.container-fluid').prepend('#{j(render(:partial => 'shared/alert_success', :locals => {:alert_message => t('.notice', :name => @stock_article.name)}))}'); + +$('#modalContainer').modal('hide'); diff --git a/app/views/deliveries/new_stock_article.js.haml b/app/views/deliveries/new_stock_article.js.haml new file mode 100644 index 00000000..92cddccd --- /dev/null +++ b/app/views/deliveries/new_stock_article.js.haml @@ -0,0 +1,2 @@ +$('#modalContainer').html('#{j(render(:partial => "stock_article_form", :locals => {:stock_article => @stock_article, :supplier => @supplier}))}'); +$('#modalContainer').modal(); diff --git a/app/views/shared/_alert_success.haml b/app/views/shared/_alert_success.haml new file mode 100644 index 00000000..3a2f5fd6 --- /dev/null +++ b/app/views/shared/_alert_success.haml @@ -0,0 +1,5 @@ +.alert.fade.in.alert-success + %a.close{:href => '#', :data => {:dismiss => 'alert'}} + = t('ui.marks.close').html_safe + = t('ui.marks.success').html_safe + = alert_message diff --git a/app/views/stockit/destroy.js.haml b/app/views/stockit/destroy.js.haml index b70b44ca..8bbde9ed 100644 --- a/app/views/stockit/destroy.js.haml +++ b/app/views/stockit/destroy.js.haml @@ -4,11 +4,5 @@ var successDiv = $('
erneut einen Lagerartikel der Lieferung hinzufügen. create: notice: Lieferung wurde erstellt. Bitte nicht vergessen die Rechnung anzulegen! destroy: @@ -424,6 +426,7 @@ de: title: Lieferung bearbeiten form: add_article: Lagerartikel der Lieferung hinzufügen + new_stock_article: Neuen Lagerartikel anlegen new_article: search: Suche nach Artikeln aus dem %{supplier} Katalog title: Neuen Lagerartikel anlegen @@ -451,6 +454,8 @@ de: unit: Einheit stock_change: remove_article: Artikel aus Lieferung entfernen + stock_article_form: + title: Lagerartikel suppliers_overview: Lieferantenübersicht update: notice: Lieferung wurde aktualisiert. @@ -1825,6 +1830,7 @@ de: edit: Bearbeiten marks: close: ! '×' + success: ! '' or_cancel: oder abbrechen save: Speichern show: Anzeigen diff --git a/config/routes.rb b/config/routes.rb index cbcf2828..391f317b 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -103,6 +103,7 @@ Foodsoft::Application.routes.draw do resources :deliveries do post :drop_stock_change, :on => :member + get :new_stock_article, :on => :collection post :add_stock_article, :on => :collection end From 49cfa9aded447ad35484b35594777c73dcfd381f Mon Sep 17 00:00:00 2001 From: Julius Date: Tue, 11 Jun 2013 15:05:19 +0200 Subject: [PATCH 08/51] Cleanup StockArticle creation during delivery --- app/controllers/deliveries_controller.rb | 14 -------------- app/views/deliveries/_form.html.haml | 10 ++++++++-- app/views/deliveries/_stock_article_form.html.haml | 2 +- config/locales/de.yml | 4 +--- 4 files changed, 10 insertions(+), 20 deletions(-) diff --git a/app/controllers/deliveries_controller.rb b/app/controllers/deliveries_controller.rb index af247462..4604c0c7 100644 --- a/app/controllers/deliveries_controller.rb +++ b/app/controllers/deliveries_controller.rb @@ -87,20 +87,6 @@ class DeliveriesController < ApplicationController else render :action => 'new_stock_article', :layout => false end - - #render :update do |page| - # if article.save - # logger.debug "new StockArticle: #{article.id}" - # page.insert_html :bottom, 'stock_changes', :partial => 'stock_change', - # :locals => {:stock_change => article.stock_changes.build, :supplier => @supplier} -# - # page.replace_html 'new_stock_article', :partial => 'stock_article_form', - # :locals => {:stock_article => @supplier.stock_articles.build} - # else - # page.replace_html 'new_stock_article', :partial => 'stock_article_form', - # :locals => {:stock_article => article} - # end - #end end def add_stock_change diff --git a/app/views/deliveries/_form.html.haml b/app/views/deliveries/_form.html.haml index bfa90114..1fb6a5ce 100644 --- a/app/views/deliveries/_form.html.haml +++ b/app/views/deliveries/_form.html.haml @@ -12,10 +12,16 @@ }) }); +- content_for :javascript do + :javascript + $(function() { + $('#add-stock-change').click(); + }); + .well.well-small .btn-toolbar .btn-group - = link_to t('.new_stock_article'), new_stock_article_supplier_deliveries_path(@supplier), remote: true, class: 'btn btn-primary' + = link_to t('.new_stock_article'), new_stock_article_supplier_deliveries_path(@supplier), remote: true, class: 'btn' = simple_form_for [@supplier, @delivery], validate: true do |f| = f.hidden_field :supplier_id @@ -28,7 +34,7 @@ = stock_change_form.hidden_field :_destroy = link_to t('.remove_article'), "#", class: 'destroy_stock_change' %p - = link_to t('.add_article'), {action: 'add_stock_change', supplier_id: @supplier.id}, remote: true, class: 'btn btn-small' + = link_to t('.add_article'), {action: 'add_stock_change', supplier_id: @supplier.id}, :id => 'add-stock-change', remote: true, class: 'btn btn-small btn-primary' %hr/ = f.input :delivered_on, as: :date_picker = f.input :note, input_html: {size: '35x4'} diff --git a/app/views/deliveries/_stock_article_form.html.haml b/app/views/deliveries/_stock_article_form.html.haml index 8384eefe..2d3b0906 100644 --- a/app/views/deliveries/_stock_article_form.html.haml +++ b/app/views/deliveries/_stock_article_form.html.haml @@ -2,7 +2,7 @@ = f.hidden_field :supplier_id .modal-header = link_to t('ui.marks.close').html_safe, '#', class: 'close', data: {dismiss: 'modal'} - %h3= t '.title' + %h3= t 'activerecord.models.stock_article' .modal-body = f.input :name = f.input :unit diff --git a/config/locales/de.yml b/config/locales/de.yml index 8d48adc0..ccd58e76 100644 --- a/config/locales/de.yml +++ b/config/locales/de.yml @@ -417,7 +417,7 @@ de: year: Jahr deliveries: add_stock_article: - notice: ! Neuer Lagerartikel »%{name}« gespeichert. Zum Auswählen bitte erneut einen Lagerartikel der Lieferung hinzufügen. + notice: Neuer Lagerartikel »%{name}« gespeichert. Zum Auswählen bitte erneut einen Lagerartikel der Lieferung hinzufügen. create: notice: Lieferung wurde erstellt. Bitte nicht vergessen die Rechnung anzulegen! destroy: @@ -454,8 +454,6 @@ de: unit: Einheit stock_change: remove_article: Artikel aus Lieferung entfernen - stock_article_form: - title: Lagerartikel suppliers_overview: Lieferantenübersicht update: notice: Lieferung wurde aktualisiert. From 65f61e09d53c293599f67b00c92e322e5544da90 Mon Sep 17 00:00:00 2001 From: Julius Date: Thu, 13 Jun 2013 23:33:24 +0200 Subject: [PATCH 09/51] Improve delivery workflow; introduce sortable tables; use js.erb for deliveries --- app/assets/javascripts/application.js | 99 ++++++++++++++-- app/controllers/deliveries_controller.rb | 85 ++++++------- app/helpers/deliveries_helper.rb | 4 + app/models/delivery.rb | 9 +- app/views/deliveries/_form.html.haml | 112 +++++++++++++----- .../_stock_article_for_adding.html.haml | 16 +++ .../deliveries/_stock_article_form.html.haml | 7 +- app/views/deliveries/_stock_change.html.haml | 15 ++- app/views/deliveries/add_stock_article.js.erb | 14 +++ .../deliveries/add_stock_article.js.haml | 3 - app/views/deliveries/add_stock_change.js.erb | 20 ++++ app/views/deliveries/add_stock_change.js.haml | 1 - .../deliveries/edit_stock_article.js.erb | 5 + app/views/deliveries/new_stock_article.js.erb | 5 + .../deliveries/new_stock_article.js.haml | 2 - .../deliveries/update_stock_article.js.erb | 35 ++++++ config/locales/de.yml | 24 +++- config/routes.rb | 6 +- 18 files changed, 357 insertions(+), 105 deletions(-) create mode 100644 app/views/deliveries/_stock_article_for_adding.html.haml create mode 100644 app/views/deliveries/add_stock_article.js.erb delete mode 100644 app/views/deliveries/add_stock_article.js.haml create mode 100644 app/views/deliveries/add_stock_change.js.erb delete mode 100644 app/views/deliveries/add_stock_change.js.haml create mode 100644 app/views/deliveries/edit_stock_article.js.erb create mode 100644 app/views/deliveries/new_stock_article.js.erb delete mode 100644 app/views/deliveries/new_stock_article.js.haml create mode 100644 app/views/deliveries/update_stock_article.js.erb diff --git a/app/assets/javascripts/application.js b/app/assets/javascripts/application.js index 04098d88..820d682c 100644 --- a/app/assets/javascripts/application.js +++ b/app/assets/javascripts/application.js @@ -10,6 +10,34 @@ //= require_self //= require ordering +// function for sorting DOM elements +$.fn.sorter = (function(){ + // Thanks to James Padolsey and Avi Deitcher + // http://james.padolsey.com/javascript/sorting-elements-with-jquery/#comment-29400 + var sort = [].sort; + + return function(comparator, getSortable) { + getSortable = getSortable || function(){return this;}; + + var sorted = sort.call(this, comparator); // sort all elements in memory + var prevElmt = null; + for(i=sorted.length-1; i>=0; --i) { // loop starting from last + var criterionElmt = sorted[i]; + var curElmt = ( 'function' === typeof getSortable ) ? ( getSortable.call(criterionElmt) ) : ( criterionElmt ); + var parent = curElmt.parentNode; + if (!prevElmt) { + parent.appendChild(curElmt); // place last element to the end + } else { + parent.insertBefore(curElmt, prevElmt); // move each element before the previous one + } + prevElmt = curElmt; + } + return sorted; + + }; + +})(); + // Load following statements, when DOM is ready $(function() { @@ -100,17 +128,74 @@ $(function() { // Use bootstrap datepicker for dateinput $('.datepicker').datepicker({format: 'yyyy-mm-dd', weekStart: 1, language: 'de'}); + + // Init table sorting + var myBars = $('span.sorter-bar'); + myBars.html(''); + $('button:nth-child(1)', myBars).click(function(e) {sortTable(e, false);}).attr('title', 'Sortiere aufsteigend'); + $('button:nth-child(2)', myBars).click(function(e) {sortTable(e, true);}).attr('title', 'Sortiere absteigend (umgekehrt)'); + + $('span.sorter-bar.default-sort-asc button:nth-child(1)').trigger('click'); + $('span.sorter-bar.default-sort-desc button:nth-child(2)').trigger('click'); }); +// parse a string to a float +function myFloatParse(input) { + var number = input.trim(); + number = number.split(' ')[0]; + number = number.replace(',', '.'); + number = parseFloat(number, 10); + return number; +} + +// compare two elements interpreted as text +function compareText(a, b) { + return $.trim(a.textContent).toLowerCase() < $.trim(b.textContent).toLowerCase() ? -1 : 1; +} + +// compare two elements interpreted as float +function compareFloat(a, b) { + a = myFloatParse( $(a).text() ); + b = myFloatParse( $(b).text() ); + return ( a