inbox_items 0.1.6

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 31c4e1e25a30d5a4a4431ac38a466ee880a50d1d
4
+ data.tar.gz: 627dd5a1fd65947d636aaf3857d16e95787b43b4
5
+ SHA512:
6
+ metadata.gz: 857cc4f293527dd8e845d601a717c7c29c8a90f740115f5150e0f0b40b78f62537ebcc98a6d33ae438ac5da9d0d779240d26123ca106a20bc31c7e8b22d5ec68
7
+ data.tar.gz: 1f1c47a6a70acc8c024e724063e3b981ec3b7a52de385a77c8c140eea1b96bd99f8cf1beda135f533c3a14540c53babf9124a0ee1ce421a8ccd4888a5fa0f4e9
data/NO-LICENSE ADDED
@@ -0,0 +1 @@
1
+ Copyright 2015 Gordon B. Isnor
data/Rakefile ADDED
@@ -0,0 +1,37 @@
1
+ begin
2
+ require 'bundler/setup'
3
+ rescue LoadError
4
+ puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
5
+ end
6
+
7
+ require 'rdoc/task'
8
+
9
+ RDoc::Task.new(:rdoc) do |rdoc|
10
+ rdoc.rdoc_dir = 'rdoc'
11
+ rdoc.title = 'InboxItems'
12
+ rdoc.options << '--line-numbers'
13
+ rdoc.rdoc_files.include('README.rdoc')
14
+ rdoc.rdoc_files.include('lib/**/*.rb')
15
+ end
16
+
17
+ APP_RAKEFILE = File.expand_path("../spec/dummy/Rakefile", __FILE__)
18
+ load 'rails/tasks/engine.rake'
19
+
20
+
21
+ load 'rails/tasks/statistics.rake'
22
+
23
+
24
+
25
+ Bundler::GemHelper.install_tasks
26
+
27
+ require 'rake/testtask'
28
+
29
+ Rake::TestTask.new(:test) do |t|
30
+ t.libs << 'lib'
31
+ t.libs << 'test'
32
+ t.pattern = 'test/**/*_test.rb'
33
+ t.verbose = false
34
+ end
35
+
36
+
37
+ task default: :test
@@ -0,0 +1,13 @@
1
+ // This is a manifest file that'll be compiled into application.js, which will include all the files
2
+ // listed below.
3
+ //
4
+ // Any JavaScript/Coffee file within this directory, lib/assets/javascripts, vendor/assets/javascripts,
5
+ // or any plugin's vendor/assets/javascripts directory can be referenced here using a relative path.
6
+ //
7
+ // It's not advisable to add code directly here, but if you do, it'll appear at the bottom of the
8
+ // compiled file.
9
+ //
10
+ // Read Sprockets README (https://github.com/sstephenson/sprockets#sprockets-directives) for details
11
+ // about supported directives.
12
+ //
13
+ //= require_tree .
@@ -0,0 +1,11 @@
1
+ var logItemsReady = function () {
2
+
3
+ $('input[name="inbox_item[convert]"]').on('switchChange.bootstrapSwitch', function (event, state) {
4
+ var target = $(this).data('target');
5
+ $(target).toggleClass('invisible');
6
+ });
7
+
8
+ };
9
+
10
+ $(document).ready(logItemsReady);
11
+ $(document).on('page:load', logItemsReady);
@@ -0,0 +1,15 @@
1
+ /*
2
+ * This is a manifest file that'll be compiled into application.css, which will include all the files
3
+ * listed below.
4
+ *
5
+ * Any CSS and SCSS file within this directory, lib/assets/stylesheets, vendor/assets/stylesheets,
6
+ * or any plugin's vendor/assets/stylesheets directory can be referenced here using a relative path.
7
+ *
8
+ * You're free to add application-wide styles to this file and they'll appear at the bottom of the
9
+ * compiled file so the styles you add here take precedence over styles defined in any styles
10
+ * defined in the other CSS/SCSS files in this directory. It is generally better to create a new
11
+ * file per style scope.
12
+ *
13
+ *= require_tree .
14
+ *= require_self
15
+ */
@@ -0,0 +1,4 @@
1
+ class InboxItems::ApplicationController < ApplicationController
2
+ end
3
+
4
+
@@ -0,0 +1,47 @@
1
+ module InboxItems
2
+ class InboxItemsController < ApplicationController
3
+
4
+ def index
5
+ @inbox_items = current_user.inbox_items.order(id: :desc).unconverted.all
6
+ end
7
+
8
+ def edit
9
+ @inbox_item = current_user.inbox_items.find(params[:id])
10
+ @inbox_item.mark_as_read! if @inbox_item.may_mark_as_read?
11
+ @inbox_item.convert = true unless @inbox_item.converted?
12
+ @inbox_item.log_type = 'lab_notes'
13
+ @inbox_item.date = @inbox_item.created_at.to_date
14
+ @projects = current_user.projects.all.collect { |p| [p.project_name, p.id] }
15
+ @inbox_item.project_id = @projects.first[1] if @projects.count == 1
16
+ end
17
+
18
+ def update
19
+ @inbox_item = current_user.inbox_items.find(params[:id])
20
+
21
+ if @inbox_item.update_attributes(item_params)
22
+ @inbox_item.convert_to_log_item! if item_params[:convert] == '1'
23
+ redirect_to inbox_items_path, notice: 'Updated'
24
+ end
25
+ end
26
+
27
+ def destroy
28
+ @inbox_item = current_user.inbox_items.find(params[:id])
29
+ @inbox_item.destroy
30
+ redirect_to inbox_items_path, notice: t(:inbox_item_was_removed)
31
+ end
32
+
33
+ def file_redirect
34
+ @inbox_item = current_user.inbox_items.find(params[:id])
35
+ @file_upload = @inbox_item.file_uploads.find(params[:file_upload_id])
36
+ redirect_to @file_upload.public_url if @file_upload.url.present?
37
+ end
38
+
39
+ def item_params
40
+ params.require(:inbox_item).permit(:subject, :body, :project_id, :log_time, :convert, :log_type, :date)
41
+ end
42
+ private :item_params
43
+
44
+ end
45
+ end
46
+
47
+
@@ -0,0 +1,4 @@
1
+ module InboxItems
2
+ module ApplicationHelper
3
+ end
4
+ end
@@ -0,0 +1,10 @@
1
+ module InboxItems
2
+ class MoveEmailAttachmentToS3Job < ActiveJob::Base
3
+ queue_as :default
4
+
5
+ def perform(file_upload)
6
+ InboxItems::MoveFileUploadToS3.call(file_upload)
7
+ end
8
+ end
9
+ end
10
+
@@ -0,0 +1,54 @@
1
+ require 'aasm'
2
+
3
+ class InboxItem < ActiveRecord::Base
4
+ include AASM
5
+
6
+ belongs_to :user
7
+ belongs_to :log_entry
8
+ has_many :file_uploads
9
+
10
+ attr_accessor :convert, :project_id, :log_time, :log_type, :date
11
+
12
+ aasm whiny_transitions: true do
13
+ state :unread, initial: true
14
+ state :read
15
+ state :converted
16
+ event :mark_as_read do
17
+ transitions from: :unread, to: :read
18
+ end
19
+ event :convert_to_log_item do
20
+ transitions from: :read, to: :converted
21
+ before do
22
+ do_conversion
23
+ end
24
+ end
25
+ end
26
+
27
+ def do_conversion
28
+ transaction do
29
+ project = user.projects.find(project_id)
30
+
31
+ l = project.log_entries.build({
32
+ user_id: user.id,
33
+ log_time: self.log_time,
34
+ date: self.date,
35
+ log_type: self.log_type,
36
+ task_name: self.subject,
37
+ task_description: self.body
38
+ })
39
+
40
+ l.save!
41
+ update_attribute(:log_entry_id, l.id)
42
+ file_uploads.update_all(log_entry_id: l.id)
43
+ end
44
+ end
45
+
46
+ def self.unread
47
+ where(aasm_state: 'unread')
48
+ end
49
+
50
+ def self.unconverted
51
+ where(aasm_state: ['unread', 'read'])
52
+ end
53
+
54
+ end
@@ -0,0 +1,77 @@
1
+ class EmailProcessor
2
+
3
+ def initialize(email)
4
+ @email = email
5
+ @user = User.find_by_email(@email.from[:email])
6
+ end
7
+
8
+ def process
9
+
10
+ inbox_item = create_inbox_item
11
+
12
+ @email.attachments.each_with_index do |attachment,i|
13
+ begin
14
+ file_upload = create_file_upload(attachment, inbox_item)
15
+ InboxItems::MoveEmailAttachmentToS3Job.perform_later(file_upload) if file_upload
16
+ rescue => e
17
+ Rails.logger.info "Rescue from error at EmailProcessor attachments each with index line 17: #{e}"
18
+ next
19
+ end
20
+ end # end each attachment
21
+
22
+ end # end process
23
+
24
+ def create_inbox_item
25
+ inbox_item = @user.inbox_items.new(subject: formatted_subject, body: @email.raw_body)
26
+ inbox_item.save
27
+ return inbox_item
28
+ rescue => e
29
+ Rails.logger.info "Rescue at Email Processor create_inbox_item, line 28: #{e}"
30
+ return nil
31
+ end
32
+
33
+ def formatted_subject
34
+ @email.subject.gsub(/FWD:|Fwd:|Fw:|Re:|RE:/, '').strip
35
+ end
36
+
37
+ def formatted_body
38
+ email.body.gsub(/Sent from my iPhone/, '')
39
+ end
40
+
41
+ def directory
42
+ File.join(Rails.root, "public", "system", "email_attachments")
43
+ end
44
+
45
+ def create_file_upload(attachment, inbox_item)
46
+ raise "No inbox item" unless inbox_item.present?
47
+
48
+ path = store_file_locally(attachment)
49
+
50
+ file_upload = FileUpload.new({
51
+ inbox_item_id: inbox_item.id,
52
+ filename: attachment.original_filename,
53
+ mime: attachment.content_type,
54
+ file_type: attachment.content_type.split('/')[0],
55
+ local_file: path,
56
+ path: path
57
+ })
58
+ file_upload.save
59
+ return file_upload
60
+ rescue => e
61
+ Rails.logger.info "Rescue at Email Processor create_file_upload line 48: #{e}"
62
+ return false
63
+ end
64
+
65
+ def store_file_locally(attachment)
66
+ name = attachment.original_filename
67
+ path = File.join(directory, name)
68
+ File.open(path, "wb") { |f| f.write(attachment.read) }
69
+ return path
70
+ rescue => e
71
+ Rails.logger.info "Rescue at EmailProcessor store_file_locally line 57: #{e}"
72
+ end
73
+
74
+ end # end email process class
75
+
76
+
77
+
@@ -0,0 +1,23 @@
1
+ module InboxItems
2
+
3
+ class MoveFileUploadToS3
4
+
5
+ def self.call(file_upload)
6
+
7
+ path = "file_uploads/#{file_upload.id}_#{file_upload.created_at.to_i}/#{file_upload.filename}"
8
+
9
+ s3file = Amazon.put({file: file_upload.local_file, path: path, bucket: Settings.s3_bucket})
10
+
11
+ if s3file
12
+ url = s3file.url_for(:read, {secure: false}).to_s.split('?')[0]
13
+ file_upload.update_attributes(url: url, path: path)
14
+ File.unlink(file_upload.local_file)
15
+ end
16
+
17
+ end
18
+
19
+ end
20
+
21
+ end
22
+
23
+
@@ -0,0 +1,23 @@
1
+ %tr{data: { toggle: 'collapse', target: "#collapse_#{inbox_item.id}"}, class: "#{'unread' if inbox_item.unread?}" }
2
+
3
+ %td.subject= link_to inbox_item.subject, edit_inbox_item_path(inbox_item)
4
+ %td.body
5
+ = inbox_item.body
6
+ %div.collapse.collapse-panel{id: "collapse_#{inbox_item.id}"}
7
+ - if inbox_item.file_uploads.any?
8
+ %ul.list-unstyled
9
+ - inbox_item.file_uploads.each do |file|
10
+ %li= link_to file.filename, file_redirect_inbox_item_path(inbox_item, file_upload_id: file.id), target: '_blank'
11
+
12
+ %td.file.text-center= glyph(:file) if inbox_item.file_uploads.present?
13
+ %td.edit.text-center
14
+ = link_to edit_inbox_item_path(inbox_item), title: t(:edit) do
15
+ %span.glyphicon.glyphicon-import
16
+ %td.remove.text-center
17
+ = link_to inbox_item_path(inbox_item), method: :delete, data:{confirm: t(:are_you_sure)}, title: t(:remove) do
18
+ = content_tag :i, nil, class: 'ion-close-circled'
19
+
20
+
21
+
22
+
23
+
@@ -0,0 +1,51 @@
1
+ :css
2
+ .unread * {
3
+ font-weight: bold;
4
+ }
5
+ #conversion {
6
+ -webkit-transition: opacity 0.25s;
7
+ transition: opacity 0.25s;
8
+ }
9
+ #conversion.invisible {
10
+ opacity: 0;
11
+ }
12
+
13
+ %br
14
+ .alert.alert-info Feel free to edit this email into a more concise log
15
+
16
+ = simple_nested_form_for @inbox_item do |f|
17
+ .menubar
18
+ .sidebar-toggler.visible-xs
19
+ %i.ion-navicon
20
+ .page-title= t(:inbox)
21
+ .content-wrapper
22
+ .row
23
+ .col-sm-12= f.input :subject
24
+ .col-sm-12= f.input :body, input_html: {rows: 4}
25
+
26
+ - unless @inbox_item.converted?
27
+ .row
28
+ .col-sm-3
29
+ = f.label :convert, 'Import'
30
+ %br
31
+ = f.check_box :convert, data: {target: '#conversion'}, class: 'switch'
32
+ %br
33
+ #conversion.col-sm-9
34
+ .row
35
+ .col-sm-4= f.input :project_id, collection: @projects, prompt: 'Project...', input_html: {class: 'chosen'}
36
+ .col-sm-4= f.input :date, input_html: {class: 'datepicker'}
37
+ .col-sm-4
38
+ %br
39
+ .btn-group{data:{toggle: 'buttons'}}
40
+ %label.btn-xs.btn.btn-primary{class: "#{'active' if f.object.log_type == 'lab_notes'}"}
41
+ = f.radio_button :log_type, 'lab_notes', autocomplete: 'off'
42
+ = t(:lab_notes)
43
+ %label.btn.btn-xs.btn-primary{class: "#{'active' if f.object.log_type == 'log_data'}"}
44
+ = f.radio_button :log_type, 'log_data', autocomplete: 'off'
45
+ = t(:log_data)
46
+ %label.btn.btn-xs.btn-primary{class: "#{'active' if f.object.log_type == 'progress'}"}
47
+ = f.radio_button :log_type, 'progress', autocomplete: 'off'
48
+ = t(:progress)
49
+
50
+ %hr
51
+ = f.submit 'Convert', class: 'btn btn-success', disable_with: t('please_wait')
@@ -0,0 +1,23 @@
1
+ .menubar
2
+ .sidebar-toggler.visible-xs
3
+ %i.ion-navicon
4
+ .page-title= t(:inbox)
5
+
6
+ .content-wrapper
7
+ %br
8
+ - if @inbox_items.blank?
9
+ %h2= t(:no_items_found)
10
+ - else
11
+ .chart
12
+ .table-responsive
13
+ %table#inbox_items.table.table-striped
14
+ %thead
15
+ %tr
16
+ %th= t(:subject)
17
+ %th= t(:body)
18
+ %th.text-center= t(:file)
19
+ %th.text-center= t(:import)
20
+ %th.text-center= t(:delete)
21
+ %tbody= render @inbox_items
22
+
23
+ = content_for :body_id, "reports"
@@ -0,0 +1,5 @@
1
+ en:
2
+ inbox: Inbox
3
+ import: Import
4
+ delete: Delete
5
+ no_items_found: No items found
data/config/routes.rb ADDED
@@ -0,0 +1,9 @@
1
+ InboxItems::Engine.routes.draw do
2
+
3
+ resources :inbox_items, path: '/' do
4
+ member do
5
+ get :file_redirect
6
+ end
7
+ end
8
+
9
+ end
@@ -0,0 +1,13 @@
1
+ class CreateInboxItems < ActiveRecord::Migration
2
+ def change
3
+ create_table :inbox_items do |t|
4
+ t.string :subject
5
+ t.text :body
6
+ t.integer :user_id
7
+ t.integer :log_entry_id
8
+ t.string :state
9
+ t.timestamps null: false
10
+ end
11
+ add_index :inbox_items, :user_id
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ class AddInboxItemIdToFileUploads < ActiveRecord::Migration
2
+ def change
3
+ add_column :file_uploads, :inbox_item_id, :integer
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class RenameStateToAasmState < ActiveRecord::Migration
2
+ def change
3
+ rename_column :inbox_items, :state, :aasm_state
4
+ end
5
+ end
@@ -0,0 +1,5 @@
1
+ class AddLocalFileToFileUploads < ActiveRecord::Migration
2
+ def change
3
+ add_column :file_uploads, :local_file, :string
4
+ end
5
+ end
@@ -0,0 +1,17 @@
1
+ module InboxItems
2
+ class Engine < ::Rails::Engine
3
+ isolate_namespace InboxItems
4
+ config.generators do |g|
5
+ g.test_framework :rspec
6
+ g.fixture_replacement :factory_girl, :dir => 'spec/factories'
7
+ end
8
+ initializer :append_migrations do |app|
9
+ unless app.root.to_s.match root.to_s
10
+ config.paths["db/migrate"].expanded.each do |expanded_path|
11
+ app.config.paths["db/migrate"] << expanded_path
12
+ end
13
+ end
14
+ end
15
+
16
+ end
17
+ end
@@ -0,0 +1,3 @@
1
+ module InboxItems
2
+ VERSION = "0.1.6"
3
+ end
@@ -0,0 +1,4 @@
1
+ require "inbox_items/engine"
2
+
3
+ module InboxItems
4
+ end
@@ -0,0 +1,4 @@
1
+ # desc "Explaining what the task does"
2
+ # task :inbox_items do
3
+ # # Task goes here
4
+ # end
metadata ADDED
@@ -0,0 +1,111 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: inbox_items
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.6
5
+ platform: ruby
6
+ authors:
7
+ - Gordon B. Isnor
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2015-11-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rails
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: 4.2.0
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: 4.2.0
27
+ - !ruby/object:Gem::Dependency
28
+ name: aasm
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: sqlite3
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ description: Inbox items engine
56
+ email:
57
+ - gordonbisnor@gmail.com
58
+ executables: []
59
+ extensions: []
60
+ extra_rdoc_files: []
61
+ files:
62
+ - NO-LICENSE
63
+ - Rakefile
64
+ - app/assets/javascripts/inbox_items/application.js
65
+ - app/assets/javascripts/inbox_items/inbox_items.js
66
+ - app/assets/stylesheets/inbox_items/application.css
67
+ - app/controllers/inbox_items/application_controller.rb
68
+ - app/controllers/inbox_items/inbox_items_controller.rb
69
+ - app/helpers/inbox_items/application_helper.rb
70
+ - app/jobs/move_email_attachment_to_s3_job.rb
71
+ - app/models/inbox_item.rb
72
+ - app/services/email_processor.rb
73
+ - app/services/move_file_upload_to_s3.rb
74
+ - app/views/inbox_items/inbox_items/_inbox_item.html.haml
75
+ - app/views/inbox_items/inbox_items/edit.html.haml
76
+ - app/views/inbox_items/inbox_items/index.html.haml
77
+ - config/locales/inbox_items.yml
78
+ - config/routes.rb
79
+ - db/migrate/20150530190623_create_inbox_items.rb
80
+ - db/migrate/20150531032517_add_inbox_item_id_to_file_uploads.rb
81
+ - db/migrate/20150601204341_rename_state_to_aasm_state.rb
82
+ - db/migrate/20150602183807_add_local_file_to_file_uploads.rb
83
+ - lib/inbox_items.rb
84
+ - lib/inbox_items/engine.rb
85
+ - lib/inbox_items/version.rb
86
+ - lib/tasks/inbox_items_tasks.rake
87
+ homepage: http://github.com/gordonbisnor/inbox_items
88
+ licenses:
89
+ - NO LICENSE
90
+ metadata: {}
91
+ post_install_message:
92
+ rdoc_options: []
93
+ require_paths:
94
+ - lib
95
+ required_ruby_version: !ruby/object:Gem::Requirement
96
+ requirements:
97
+ - - ">="
98
+ - !ruby/object:Gem::Version
99
+ version: '0'
100
+ required_rubygems_version: !ruby/object:Gem::Requirement
101
+ requirements:
102
+ - - ">="
103
+ - !ruby/object:Gem::Version
104
+ version: '0'
105
+ requirements: []
106
+ rubyforge_project:
107
+ rubygems_version: 2.2.2
108
+ signing_key:
109
+ specification_version: 4
110
+ summary: Inbox items engine
111
+ test_files: []