mirror of
https://github.com/TracksApp/tracks.git
synced 2026-02-12 18:34:22 +01:00
Merge branch 'master' into new-gui
Conflicts: Gemfile.lock
This commit is contained in:
commit
463f5e922d
37 changed files with 1083 additions and 501 deletions
|
|
@ -16,16 +16,29 @@ class DataController < ApplicationController
|
|||
redirect_to :back
|
||||
else
|
||||
@import_to = params[:import_to]
|
||||
|
||||
#get column headers and formart as [['name', column_number]...]
|
||||
i = -1
|
||||
@headers = import_headers(params[:file].path).collect { |v| [v, i+=1] }
|
||||
@headers.unshift ['',i]
|
||||
|
||||
begin
|
||||
#get column headers and format as [['name', column_number]...]
|
||||
i = -1
|
||||
@headers = import_headers(params[:file].path).collect { |v| [v, i+=1] }
|
||||
@headers.unshift ['',i]
|
||||
rescue Exception => e
|
||||
flash[:error] = "Invalid CVS: could not read headers: #{e}"
|
||||
redirect_to :back
|
||||
return
|
||||
end
|
||||
|
||||
#save file for later
|
||||
directory = "public/uploads/csv"
|
||||
@path = File.join(directory, params[:file].original_filename)
|
||||
File.open(@path, "wb") { |f| f.write(params[:file].read) }
|
||||
begin
|
||||
uploaded_file = params[:file]
|
||||
@filename = Tracks::Utils.sanitize_filename(uploaded_file.original_filename)
|
||||
path_and_file = Rails.root.join('public', 'uploads', 'csv', @filename)
|
||||
File.open(path_and_file, "wb") { |f| f.write(uploaded_file.read) }
|
||||
rescue Exception => e
|
||||
flash[:error] = "Could not save uploaded CSV (#{path_and_file}). Can Tracks write to the upload directory? #{e}"
|
||||
redirect_to :back
|
||||
return
|
||||
end
|
||||
|
||||
case @import_to
|
||||
when 'projects'
|
||||
|
|
@ -44,12 +57,14 @@ class DataController < ApplicationController
|
|||
|
||||
def csv_import
|
||||
begin
|
||||
filename = Tracks::Utils.sanitize_filename(params[:file])
|
||||
path_and_file = Rails.root.join('public', 'uploads', 'csv', filename)
|
||||
case params[:import_to]
|
||||
when 'projects'
|
||||
count = Project.import params, current_user
|
||||
count = Project.import path_and_file, params, current_user
|
||||
flash[:notice] = "#{count} Projects imported"
|
||||
when 'todos'
|
||||
count = Todo.import params, current_user
|
||||
count = Todo.import path_and_file, params, current_user
|
||||
flash[:notice] = "#{count} Todos imported"
|
||||
else
|
||||
flash[:error] = t('data.invalid_import_destination')
|
||||
|
|
@ -57,11 +72,11 @@ class DataController < ApplicationController
|
|||
rescue Exception => e
|
||||
flash[:error] = t('data.invalid_import_destination') + ": #{e}"
|
||||
end
|
||||
File.delete(params[:file])
|
||||
File.delete(path_and_file)
|
||||
redirect_to import_data_path
|
||||
end
|
||||
|
||||
def import_headers file
|
||||
def import_headers(file)
|
||||
CSV.foreach(file, headers: false) do |row|
|
||||
return row
|
||||
end
|
||||
|
|
@ -105,13 +120,14 @@ class DataController < ApplicationController
|
|||
send_data(result, :filename => "tracks_backup.yml", :type => 'text/plain')
|
||||
end
|
||||
|
||||
# export all actions as csv
|
||||
def csv_actions
|
||||
content_type = 'text/csv'
|
||||
CSV::Writer.generate(result = "") do |csv|
|
||||
CSV.generate(result = "") do |csv|
|
||||
csv << ["id", "Context", "Project", "Description", "Notes", "Tags",
|
||||
"Created at", "Due", "Completed at", "User ID", "Show from",
|
||||
"state"]
|
||||
current_user.todos.include(:context, :project).all.each do |todo|
|
||||
current_user.todos.includes(:context, :project, :taggings, :tags).each do |todo|
|
||||
csv << [todo.id, todo.context.name,
|
||||
todo.project_id.nil? ? "" : todo.project.name,
|
||||
todo.description,
|
||||
|
|
@ -127,7 +143,7 @@ class DataController < ApplicationController
|
|||
send_data(result, :filename => "todos.csv", :type => content_type)
|
||||
end
|
||||
|
||||
|
||||
# export all notes as csv
|
||||
def csv_notes
|
||||
content_type = 'text/csv'
|
||||
CSV.generate(result = "") do |csv|
|
||||
|
|
|
|||
38
app/controllers/mailgun_controller.rb
Normal file
38
app/controllers/mailgun_controller.rb
Normal file
|
|
@ -0,0 +1,38 @@
|
|||
require 'openssl'
|
||||
|
||||
class MailgunController < ApplicationController
|
||||
|
||||
skip_before_filter :login_required, :only => [:mailgun]
|
||||
before_filter :verify, :only => [:mailgun]
|
||||
protect_from_forgery with: :null_session
|
||||
|
||||
def mailgun
|
||||
unless params.include? 'body-mime'
|
||||
Rails.logger.info "Cannot process Mailgun request, no body-mime sent"
|
||||
render_failure "Unacceptable body-mime", 406
|
||||
return
|
||||
end
|
||||
|
||||
todo = MessageGateway.receive(params['body-mime'])
|
||||
if todo
|
||||
render :xml => todo.to_xml( *todo_xml_params )
|
||||
else
|
||||
render_failure "Todo not saved", 406
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def verify
|
||||
unless params['signature'] == OpenSSL::HMAC.hexdigest(
|
||||
OpenSSL::Digest::Digest.new('sha256'),
|
||||
SITE_CONFIG['mailgun_api_key'],
|
||||
'%s%s' % [params['timestamp'], params['token']]
|
||||
)
|
||||
Rails.logger.info "Cannot verify Mailgun signature"
|
||||
render_failure "Access denied", 406
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
|
@ -137,8 +137,8 @@ class ProjectsController < ApplicationController
|
|||
limit(current_user.prefs.show_number_completed).
|
||||
includes(Todo::DEFAULT_INCLUDES) unless @max_completed == 0
|
||||
|
||||
@count = @not_done_todos.size
|
||||
@down_count = @count + @deferred_todos.size + @pending_todos.size
|
||||
@down_count = @not_done_todos.size + @deferred_todos.size + @pending_todos.size
|
||||
@count=@down_count
|
||||
@next_project = current_user.projects.next_from(@project)
|
||||
@previous_project = current_user.projects.previous_from(@project)
|
||||
@default_tags = @project.default_tags
|
||||
|
|
|
|||
|
|
@ -87,7 +87,8 @@ class TodosController < ApplicationController
|
|||
p.parse_dates() unless mobile?
|
||||
tag_list = p.tag_list
|
||||
|
||||
@todo = current_user.todos.build(p.attributes)
|
||||
@todo = current_user.todos.build
|
||||
@todo.assign_attributes(p.attributes)
|
||||
p.add_errors(@todo)
|
||||
|
||||
if @todo.errors.empty?
|
||||
|
|
@ -125,6 +126,8 @@ class TodosController < ApplicationController
|
|||
determine_down_count
|
||||
@contexts = current_user.contexts
|
||||
@projects = current_user.projects
|
||||
@context = @todo.context
|
||||
@project = @todo.project
|
||||
@initial_context_name = params['default_context_name']
|
||||
@initial_project_name = params['default_project_name']
|
||||
@initial_tags = params['initial_tag_list']
|
||||
|
|
@ -1170,18 +1173,18 @@ end
|
|||
def update_context
|
||||
@context_changed = false
|
||||
if params['todo']['context_id'].blank? && params['context_name'].present?
|
||||
context = current_user.contexts.where(:name => params['context_name'].strip).first
|
||||
unless context
|
||||
@context = current_user.contexts.where(:name => params['context_name'].strip).first
|
||||
if @context.nil?
|
||||
@new_context = current_user.contexts.build
|
||||
@new_context.name = params['context_name'].strip
|
||||
@new_context.save
|
||||
@new_context_created = true
|
||||
@new_container = @new_context
|
||||
@not_done_todos = [@todo]
|
||||
context = @new_context
|
||||
@context = @new_context
|
||||
end
|
||||
params["todo"]["context_id"] = context.id
|
||||
@context_changed = @original_item_context_id != params["todo"]["context_id"] = context.id
|
||||
params["todo"]["context_id"] = @context.id
|
||||
@context_changed = @original_item_context_id != params["todo"]["context_id"] = @context.id
|
||||
end
|
||||
end
|
||||
|
||||
|
|
|
|||
|
|
@ -565,6 +565,13 @@ module TodosHelper
|
|||
return false
|
||||
end
|
||||
|
||||
def should_show_empty_container
|
||||
source_view do |page|
|
||||
page.context { return @remaining_in_context == 0 }
|
||||
end
|
||||
return @down_count==0
|
||||
end
|
||||
|
||||
def project_container_id(todo)
|
||||
return "p#{todo.project_id}" unless todo.project.nil?
|
||||
return "without_project_container"
|
||||
|
|
|
|||
|
|
@ -27,6 +27,7 @@ class MessageGateway < ActionMailer::Base
|
|||
todo = todo_builder.construct
|
||||
todo.save!
|
||||
Rails.logger.info "Saved email as todo for user #{user.login} in context #{context.name}"
|
||||
todo
|
||||
end
|
||||
|
||||
private
|
||||
|
|
@ -49,10 +50,26 @@ class MessageGateway < ActionMailer::Base
|
|||
if user.nil?
|
||||
user = User.where("preferences.sms_email" => address.strip[1.100]).includes(:preference).first
|
||||
end
|
||||
if user.present? and !sender_is_in_mailmap?(user,email)
|
||||
Rails.logger.warn "#{email.from[0]} not found in mailmap for #{user.login}"
|
||||
return nil
|
||||
end
|
||||
Rails.logger.info(!user.nil? ? "Email belongs to #{user.login}" : "User unknown")
|
||||
return user
|
||||
end
|
||||
|
||||
|
||||
def sender_is_in_mailmap?(user,email)
|
||||
if SITE_CONFIG['mailmap'].is_a? Hash and SITE_CONFIG['email_dispatch'] == 'to'
|
||||
# Look for the sender in the map of allowed senders
|
||||
SITE_CONFIG['mailmap'][user.preference.sms_email].include? email.from[0]
|
||||
else
|
||||
# We can't check the map if it's not defined, or if the lookup is the
|
||||
# wrong way round, so just allow it
|
||||
true
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
def get_user_from_email_address(email)
|
||||
SITE_CONFIG['email_dispatch'] == 'single_user' ? get_user_from_env_setting : get_user_from_mail_header(email)
|
||||
end
|
||||
|
|
|
|||
|
|
@ -138,9 +138,9 @@ class Project < ActiveRecord::Base
|
|||
@age_in_days ||= ((Time.now.utc - created_at).to_i / 1.day) + 1
|
||||
end
|
||||
|
||||
def self.import(params, user)
|
||||
def self.import(filename, params, user)
|
||||
count = 0
|
||||
CSV.foreach(params[:file], headers: true) do |row|
|
||||
CSV.foreach(filename, headers: true) do |row|
|
||||
unless find_by_name_and_user_id row[params[:name].to_i], user.id
|
||||
project = new
|
||||
project.name = row[params[:name].to_i]
|
||||
|
|
|
|||
|
|
@ -147,7 +147,7 @@ class RecurringTodo < ActiveRecord::Base
|
|||
end
|
||||
|
||||
def daily_every_x_days=(x)
|
||||
every_other1 = x if recurring_period=='daily'
|
||||
self.every_other1 = x if recurring_period=='daily'
|
||||
end
|
||||
|
||||
def daily_every_x_days
|
||||
|
|
@ -489,7 +489,7 @@ class RecurringTodo < ActiveRecord::Base
|
|||
|
||||
case self.recurrence_selector
|
||||
when 0 # specific day of the month
|
||||
if start.mday > day
|
||||
if (previous && start.mday >= day) || (previous.nil? && start.mday > day)
|
||||
# there is no next day n in this month, search in next month
|
||||
#
|
||||
# start += n.months
|
||||
|
|
|
|||
|
|
@ -399,11 +399,11 @@ class Todo < ActiveRecord::Base
|
|||
end
|
||||
end
|
||||
|
||||
def self.import(params, user)
|
||||
default_context = Context.where(:user_id=>user.id).order('id').first
|
||||
def self.import(filename, params, user)
|
||||
default_context = user.contexts.order('id').first
|
||||
|
||||
count = 0
|
||||
CSV.foreach(params[:file], headers: true) do |row|
|
||||
CSV.foreach(filename, headers: true) do |row|
|
||||
unless find_by_description_and_user_id row[params[:description].to_i], user.id
|
||||
todo = new
|
||||
todo.user = user
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@
|
|||
<%= select_tag(l, options_for_select(@headers) ) %>
|
||||
<br>
|
||||
<% end %>
|
||||
<%= hidden_field_tag :file, @path %>
|
||||
<%= hidden_field_tag :file, @filename %>
|
||||
<%= hidden_field_tag :import_to, @import_to %>
|
||||
<%= submit_tag "Import" %>
|
||||
<% end %>
|
||||
|
|
@ -42,7 +42,7 @@ function remove_todo(next_steps) {
|
|||
|
||||
function add_to_existing_container(next_steps) {
|
||||
$('#<%= item_container_id(@todo) %>_items').append(html_for_todo());
|
||||
<% if source_view_is_one_of(:project,:calendar) -%>
|
||||
<% if source_view_is_one_of(:calendar) -%>
|
||||
next_steps.go();
|
||||
<% if (@target_context_count==1) || ( (@todo.deferred? || @todo.pending?) && @remaining_deferred_or_pending_count == 1) -%>
|
||||
$("#<%= empty_container_msg_div_id %>").slideUp(100);
|
||||
|
|
@ -83,7 +83,7 @@ function highlight_updated_todo(next_steps) {
|
|||
}
|
||||
|
||||
function update_empty_container(next_steps) {
|
||||
<% if @down_count==0 -%>
|
||||
<% if should_show_empty_container -%>
|
||||
$('div#no_todos_in_view').slideDown(400, function(){ next_steps.go(); });
|
||||
<% else -%>
|
||||
$('div#no_todos_in_view').fadeOut(100, function(){ next_steps.go(); });
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue