wco_models 3.1.0.269 → 3.1.0.271

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (59) hide show
  1. checksums.yaml +4 -4
  2. data/README.txt +10 -12
  3. data/app/assets/stylesheets/wco/main.scss +24 -0
  4. data/app/assets/stylesheets/wco/newsvideos.scss +45 -0
  5. data/app/controllers/wco/api_controller.rb +2 -2
  6. data/app/controllers/wco/application_controller.rb +45 -0
  7. data/app/controllers/wco/leads_controller.rb +0 -2
  8. data/app/controllers/wco/newspartials_controller.rb +1 -1
  9. data/app/controllers/wco/newsvideos_controller.rb +3 -2
  10. data/app/controllers/wco/publishers_controller.rb +12 -4
  11. data/app/controllers/wco/reports_controller.rb +140 -0
  12. data/app/controllers/wco/tags_controller.rb +18 -5
  13. data/app/controllers/wco/videos_controller.rb +4 -0
  14. data/app/mailers/wco_email/application_mailer.rb +1 -1
  15. data/app/models/ability.rb +3 -0
  16. data/app/models/iro/option.rb +2 -3
  17. data/app/models/iro/position.rb +92 -27
  18. data/app/models/iro/purse.rb +1 -2
  19. data/app/models/iro/stock.rb +20 -0
  20. data/app/models/iro/strategy.rb +57 -40
  21. data/app/models/tda/option.rb +1 -1
  22. data/app/models/tda/order.rb +4 -4
  23. data/app/models/wco/lead.rb +6 -5
  24. data/app/models/wco/newspartial.rb +7 -2
  25. data/app/models/wco/newsvideo.rb +2 -0
  26. data/app/models/wco/photo.rb +2 -0
  27. data/app/models/wco/profile.rb +6 -0
  28. data/app/models/wco/publisher.rb +3 -3
  29. data/app/models/wco/report.rb +6 -3
  30. data/app/models/wco/site.rb +2 -2
  31. data/app/models/wco/tag.rb +3 -0
  32. data/app/models/wco/video.rb +28 -3
  33. data/app/models/wco_email/email_filter.rb +1 -1
  34. data/app/models/wco_email/email_filter_action.rb +2 -0
  35. data/app/models/wco_email/email_filter_condition.rb +29 -14
  36. data/app/models/wco_email/message_stub.rb +2 -1
  37. data/app/views/wco/_main_footer.haml +4 -3
  38. data/app/views/wco/_main_header.haml +1 -0
  39. data/app/views/wco/_sidebar.haml +21 -0
  40. data/app/views/wco/newsoverlays/_show_in_newsvideo.haml +7 -5
  41. data/app/views/wco/newspartials/_show_in_newsvideo.haml +35 -28
  42. data/app/views/wco/newspartials/edit.haml +4 -0
  43. data/app/views/wco/newsvideos/_form.haml +10 -3
  44. data/app/views/wco/newsvideos/show.haml +20 -3
  45. data/app/views/wco/profiles/_form.haml +33 -13
  46. data/app/views/wco/publishers/_post_with.haml +7 -0
  47. data/app/views/wco/reports/_form.haml +11 -2
  48. data/app/views/wco/reports/_to_facebook.html +23 -0
  49. data/app/views/wco/reports/show.haml +15 -0
  50. data/app/views/wco/tags/_index_table.haml +4 -1
  51. data/app/views/wco/tags/_index_tree.haml +2 -1
  52. data/app/views/wco/tags/new_for_sidebar.haml +9 -0
  53. data/app/views/wco/tags/show.haml +54 -42
  54. data/app/views/wco/tags/show.haml-bk +63 -0
  55. data/config/initializers/08_integrations.rb +0 -15
  56. data/config/routes.rb +11 -2
  57. data/lib/wco/facebook_poster.rb +17 -0
  58. metadata +23 -3
  59. data/app/views/wco/newspartials/index.haml-trash +0 -6
@@ -1,5 +1,6 @@
1
1
 
2
2
  require 'mongoid_paperclip'
3
+ require 'streamio-ffmpeg'
3
4
 
4
5
  class Wco::Video
5
6
  include Mongoid::Document
@@ -33,9 +34,6 @@ class Wco::Video
33
34
 
34
35
  field :duration_ms, type: :integer
35
36
 
36
- # belongs_to :user_profile, :class_name => 'Ish::UserProfile', :inverse_of => :videos
37
- # has_and_belongs_to_many :shared_profiles, :class_name => 'Ish::UserProfile', :inverse_of => :shared_videos
38
-
39
37
  belongs_to :lead, optional: true
40
38
  belongs_to :newspartial, optional: true
41
39
  belongs_to :newsvideo, optional: true
@@ -77,10 +75,37 @@ class Wco::Video
77
75
  %w| name descr |
78
76
  end
79
77
 
78
+ before_create :set_duration_ms
79
+ def set_duration_ms
80
+ return unless video.queued_for_write[:original]
81
+ path = video.queued_for_write[:original].path
82
+ movie = ::FFMPEG::Movie.new(path)
83
+ self.duration_ms = (movie.duration * 1000).to_i if movie.duration
84
+ end
85
+
86
+ before_create :set_title
87
+ def set_title
88
+ return unless video.present?
89
+ filename = video_file_name # Paperclip metadata
90
+ return unless filename
91
+ self.name = File.basename(filename, ".*") if self.name.blank?
92
+ end
93
+
80
94
  def self.list
81
95
  [['', nil]] + self.unscoped.order_by( :created_at => :desc ).map do |item|
82
96
  [ "#{item.created_at.strftime('%Y%m%d')} #{item.name}", item.id ]
83
97
  end
84
98
  end
85
99
 
100
+ def generate_thumbnail
101
+ return unless video.queued_for_write[:original]
102
+
103
+ input_path = video.queued_for_write[:original].path
104
+ output_path = Rails.root.join('tmp', "thumb_#{SecureRandom.hex}.jpg")
105
+ movie = ::FFMPEG::Movie.new(input_path)
106
+ movie.screenshot(output_path.to_s, seek_time: 1) ## at time 00:00:01 seconds
107
+ self.thumb = File.open(output_path)
108
+ File.delete(output_path) if File.exist?(output_path)
109
+ end
110
+
86
111
  end
@@ -28,7 +28,7 @@ class WcoEmail::EmailFilter
28
28
 
29
29
  has_many :actions, class_name: '::WcoEmail::EmailFilterAction', inverse_of: :email_filter
30
30
  accepts_nested_attributes_for :actions, allow_destroy: true, reject_if: :all_blank
31
- # validate :validate_actions
31
+ validate :validate_actions
32
32
  def validate_actions
33
33
  if actions.length == 0
34
34
  errors.add(:actions, 'must be present')
@@ -22,6 +22,7 @@ class WcoEmail::EmailFilterAction
22
22
  field :value
23
23
 
24
24
  belongs_to :aject, polymorphic: true # , optional: true # eg tag, EAT, OAT
25
+ accepts_nested_attributes_for :aject, allow_destroy: true, reject_if: :all_blank
25
26
  # validates :aject_id, presence: true
26
27
 
27
28
  ## 2026-04-02 not anymore.
@@ -46,3 +47,4 @@ class WcoEmail::EmailFilterAction
46
47
  end
47
48
 
48
49
  end
50
+ EFA = WcoEmail::EmailFilterAction
@@ -8,26 +8,40 @@ class WcoEmail::EmailFilterCondition
8
8
  belongs_to :email_filter, class_name: '::WcoEmail::EmailFilter', inverse_of: :conditions, optional: true
9
9
  belongs_to :email_skip_filter, class_name: '::WcoEmail::EmailFilter', inverse_of: :skip_conditions, optional: true
10
10
 
11
- FIELD_BODY = 'body'
12
- FIELD_BODY_PLAIN = 'body-plain'
13
- FIELD_FROM = 'from'
14
- FIELD_TAGGED = 'leadset-tagged'
11
+ FIELD_BODY = 'body'
12
+ FIELD_BODY_PLAIN = 'body-plain'
13
+ FIELD_FROM = 'from'
14
+ FIELD_LEADSET = 'from-leadset'
15
15
  FIELD_NOT_TAGGED = 'leadset-not-tagged'
16
- FIELD_SUBJECT = 'subject'
17
- # FIELD_TO = 'to'
18
- FIELD_TO_OR_CC = 'to-or-cc'
19
- FIELD_OPTS = [ FIELD_SUBJECT, FIELD_FROM, FIELD_TO_OR_CC, FIELD_TAGGED, FIELD_NOT_TAGGED, FIELD_BODY, FIELD_BODY_PLAIN ]
16
+ FIELD_SUBJECT = 'subject'
17
+ FIELD_TAGGED = 'leadset-tagged'
18
+ FIELD_TO_OR_CC = 'to-or-cc'
19
+ FIELD_OPTS = [
20
+ FIELD_BODY, FIELD_BODY_PLAIN,
21
+ FIELD_FROM,
22
+ FIELD_LEADSET,
23
+ FIELD_NOT_TAGGED,
24
+ FIELD_SUBJECT,
25
+ FIELD_TAGGED,
26
+ FIELD_TO_OR_CC,
27
+ ];
20
28
  field :field
21
29
  validates :field, presence: true, inclusion: FIELD_OPTS
22
30
 
23
31
  OPERATOR_EQUALS = 'eq-i'
24
- # OPERATOR_HAS_TAG = 'has-tag'
25
- # OPERATOR_NOT_HAS_TAG = 'not-has-tag'
32
+ OPERATOR_HAS_TAG = 'has-tag'
33
+ OPERATOR_NOT_HAS_TAG = 'not-has-tag'
26
34
  OPERATOR_REGEX = 'regex'
27
35
  OPERATOR_MATCH = 'match-i'
28
- OPERATOR__ID = '_id'
29
- OPERATOR_SLUG = 'slug'
30
- OPERATOR_OPTS = [ OPERATOR_REGEX, OPERATOR_MATCH, OPERATOR__ID, OPERATOR_SLUG ]
36
+ OPERATOR__ID = '_id'
37
+ OPERATOR_SLUG = 'slug'
38
+ OPERATOR_OPTS = [ OPERATOR__ID,
39
+ OPERATOR_EQUALS,
40
+ OPERATOR_HAS_TAG,
41
+ OPERATOR_MATCH,
42
+ OPERATOR_NOT_HAS_TAG,
43
+ OPERATOR_REGEX,
44
+ OPERATOR_SLUG, ]
31
45
  field :operator
32
46
  validates :operator, presence: true, inclusion: OPERATOR_OPTS
33
47
 
@@ -73,5 +87,6 @@ class WcoEmail::EmailFilterCondition
73
87
  "#{" " * indent }<EF#{email_skip_filter ? 'Skip' : ''}Condition #{field} #{operator} `#{value}` />\n"
74
88
  end
75
89
 
76
- end
77
90
 
91
+ end
92
+ ::EFC = ::WcoEmail::EmailFilterCondition
@@ -186,6 +186,7 @@ class WcoEmail::MessageStub
186
186
 
187
187
 
188
188
  def do_process
189
+ ## _TODO: remove this fork, be consistent across environments. _vp_ 2026-06-22
189
190
  if Rails.env.production?
190
191
  @client ||= Aws::S3::Client.new({
191
192
  region: ::S3_CREDENTIALS[:region_ses],
@@ -389,7 +390,7 @@ class WcoEmail::MessageStub
389
390
  end
390
391
  end
391
392
 
392
- puts 'ok'
393
+ puts 'stub-ok'
393
394
  end
394
395
 
395
396
  ## This only saves a local message from mbox to s3.
@@ -17,9 +17,9 @@
17
17
  %ul
18
18
  %li
19
19
  <b>Email:</b> #{@current_profile.email}
20
- = button_to 'Logout', main_app.destroy_user_session_path, :method => :delete, data: { confirm: 'Are you sure?' }
20
+ .d-inline-block= button_to 'Logout', main_app.destroy_user_session_path, :method => :delete, data: { confirm: 'Are you sure?' }
21
21
  %li= link_to 'sidekiq', '/sidekiq', target: :_blank
22
- %li= link_to 'Iron Warbler', '/iron_warbler'
22
+ %li= link_to 'RTEditor', wco.application_tinymce_path, target: :_blank
23
23
 
24
24
 
25
25
  .col-sm-4
@@ -28,10 +28,11 @@
28
28
  %li
29
29
  = pp_date Time.now
30
30
  = pp_time Time.now
31
+ %li wco_models: v#{File.read(Gem.loaded_specs["wco_models"].full_gem_path + '/VERSION')}
31
32
 
32
33
  .col-sm-4
33
34
  = render '/wco/profiles/form_extra', profile: @current_profile
34
- = link_to 'RTEditor', wco.application_tinymce_path, target: :_blank
35
+
35
36
  = render 'wco/application/debug' if !Rails.env.production?
36
37
 
37
38
  .c
@@ -19,6 +19,7 @@
19
19
  %li= link_to '/hosting', '/hosting'
20
20
  - if defined? iro
21
21
  %li= link_to '/trading', '/trading'
22
+ %li= link_to '[linkedin sync]', wco.linkedin_sync_path
22
23
 
23
24
  %ul
24
25
  %li= render '/wco/invoices/header'
@@ -0,0 +1,21 @@
1
+
2
+ .application--sidebar
3
+ sidebar tags
4
+ = link_to '[+]', wco.new_sidebar_tag_path
5
+ (#{@sidebar_tags.length}):
6
+ %ul.mr-2
7
+ - @sidebar_tags.each do |si_tag|
8
+ %li.text-nowrap= link_to si_tag, wco.tag_show2_path(si_tag)
9
+
10
+ %i.fa.fa-compress.collapse-expand{ id: 'allTags' } all tags:
11
+ %ul.tags-list
12
+ - @tags.each do |tag|
13
+ %li
14
+ = link_to tag.slug, wco.tag_path( tag )
15
+ - if defined?( wco_email )
16
+ = link_to '[convs]', wco_email.conversations_in_path( tag.slug )
17
+ -# <b>#{tag.conversations.unread.length}</b>
18
+ -# (#{tag.conversations.length})
19
+ \|
20
+ = link_to "not", wco_email.conversations_not_in_path( tag.slug )
21
+
@@ -1,10 +1,12 @@
1
-
1
+ -## no id here, it won't stay closed.
2
+ .absolute.collapse-expand{ style: "top: #{newsoverlay.start_at_ms*HEIGHT_MS}px; left: 200px;" }
3
+ <>
2
4
  .NewsoverlayTimeline{ style: "top: #{newsoverlay.start_at_ms*HEIGHT_MS}px; height: #{newsoverlay.duration_ms*HEIGHT_MS}px;"}
3
5
  .d-flex
4
6
  = newsoverlay.name
5
7
  = link_to '[~]', edit_newsoverlay_path(newsoverlay)
6
8
  = button_to 'x', newsoverlay_path(newsoverlay), method: :delete, data: { confirm: 'Are you sure?' }
7
-
8
- %img{ src: newsoverlay.video.thumb.url(:thumb) }
9
- .a start_at: #{newsoverlay.start_at_ms}ms
10
- .a Duration: #{newsoverlay.duration_ms}ms
9
+ .moreC
10
+ %img{ src: newsoverlay.video.thumb.url(:thumb) }
11
+ .a start_at: #{newsoverlay.start_at_ms}ms
12
+ .a Duration: #{newsoverlay.duration_ms}ms
@@ -1,32 +1,39 @@
1
1
 
2
- .NewspartialTimeline{ style: "height: #{newspartial.duration_ms*HEIGHT_MS}px; min-height: 100px;" }
3
- .main
4
- - newspartial.config['wtimes']&.each_with_index do |wtime, idx|
2
+ .NewspartialTimelineW
3
+ .zero-height.collapse-expand{ id: "#{newspartial.id.to_s}-wrapped-1" } <>
4
+ .NewspartialTimeline{ style: "height: #{newspartial.duration_ms*HEIGHT_MS}px; min-height: 100px;" }
5
5
 
6
- %div.timestamp{ style: "top: #{wtime.to_f*HEIGHT_MS}px"}
7
- .wtime= wtime
8
- .word= newspartial.config['words'][idx]
6
+ .main
7
+ - newspartial.config['wtimes']&.each_with_index do |wtime, idx|
9
8
 
10
- .full-text
11
- .header
12
- Newspartial
13
- = link_to '[~]', edit_newspartial_path(newspartial)
14
- .d-inline-block= button_to 'x', newspartial_path(newspartial), method: :delete, :data => { :confirm => 'Are you sure?' }
15
- %span{ class: 'gray' } #{newspartial.id}
16
- = link_to '[api]', api_newspartial_config_path(newspartial, format: :json, api_key: SIMPLE_API_KEY, api_secret: SIMPLE_API_SECRET ), target: :_blank
9
+ %div.timestamp{ style: "top: #{wtime.to_f*HEIGHT_MS}px"}
10
+ .wtime= wtime
11
+ .word= newspartial.config['words'][idx]
17
12
 
18
- .flex-row
19
- .a Duration: `#{newspartial.duration_ms}`ms
20
- .descr= newspartial.body
21
- .d-flex.flex-column
22
- = button_to 'Generate video', newspartial_generate_video_path(newspartial)
23
- Video:
24
- - if newspartial.video
25
- = image_tag newspartial.video.thumb.url(:thumb), class: 'thumb'
26
- .d-flex.flex-column
27
- = button_to 'Generate speech', newspartial_generate_speech_path(newspartial)
28
- Audio:
29
- - if newspartial.audio.present?
30
- %audio{ controls: true }
31
- %source{ src: newspartial.audio, type: "audio/wav" }
32
- Your browser does not support the audio element.
13
+
14
+ .full-text
15
+ .header.collapse-expand{ id: newspartial.id.to_s }
16
+ Newspartial
17
+ = link_to '[~]', edit_newspartial_path(newspartial)
18
+ .d-inline-block= button_to 'x', newspartial_path(newspartial), method: :delete, :data => { :confirm => 'Are you sure?' }
19
+ %span{ class: 'gray' } #{newspartial.id}
20
+ = link_to '[api]', api_newspartial_config_path(newspartial, format: :json, api_key: WCO_SIMPLE_API_KEY, api_secret: WCO_SIMPLE_API_SECRET ), target: :_blank
21
+
22
+ .full-textC
23
+ .flex-row
24
+ .a Duration: `#{newspartial.duration_ms}`ms
25
+ .descr= newspartial.body
26
+ .d-flex.flex-column
27
+ = button_to 'Generate video', newspartial_generate_video_path(newspartial), :data => { :confirm => 'Are you sure?' }
28
+ .small.gray ISHLIB3JS_ROOT
29
+ Video:
30
+ - if newspartial.video
31
+ = image_tag newspartial.video.thumb.url(:thumb), class: 'thumb'
32
+ .d-flex.flex-column
33
+ = button_to 'Generate speech', newspartial_generate_speech_path(newspartial), :data => { :confirm => 'Are you sure?' }
34
+ .small.gray Requires HeadTTS.git on :8882
35
+ Audio:
36
+ - if newspartial.audio.present?
37
+ %audio{ controls: true }
38
+ %source{ src: newspartial.audio, type: "audio/wav" }
39
+ Your browser does not support the audio element.
@@ -0,0 +1,4 @@
1
+
2
+ .newspartials-new.maxwidth
3
+ %h5 Edit Newspartial
4
+ = render 'form', newspartial: @newspartial
@@ -11,9 +11,16 @@
11
11
  %label Slug
12
12
  = f.text_field :slug, class: 'w-100'
13
13
 
14
- .field
15
- %label deleted_at
16
- = f.text_field :deleted_at
14
+ .row
15
+ .field
16
+ %label deleted_at
17
+ = f.text_field :deleted_at
18
+ .field
19
+ %label w_px
20
+ = f.text_field :w_px
21
+ .field
22
+ %label h_px
23
+ = f.text_field :h_px
17
24
 
18
25
  .field
19
26
  %label Body
@@ -3,16 +3,33 @@
3
3
  %h5.text-center
4
4
  Newsvideo `#{@newsvideo.title}`
5
5
  #{link_to '[~]', edit_newsvideo_path(@newsvideo)}
6
- .d-inline-block= button_to 'split', split_newsvideo_path(@newsvideo), :data => { :confirm => 'Are you sure?' }
6
+
7
7
  = link_to '[+ newspartial]', new_newspartial_path(newsvideo_id: @newsvideo.id)
8
8
  = link_to '[search illustration]', pexels_search_path(newsvideo_id: @newsvideo.id), target: :_blank
9
- .d-inline-block= button_to 'generate', generate_newsvideo_path(@newsvideo), :data => { :confirm => 'Are you sure?' }
10
9
 
11
- .descr= @newsvideo.body
10
+
11
+ %ul.actions
12
+ %li
13
+ .d-inline-block= button_to 'split', split_newsvideo_path(@newsvideo), :data => { :confirm => 'Are you sure?' }
14
+ .small.gray
15
+ Uses sentences_to_phrases to reasonably create Wco::Newspartial's
16
+ %li
17
+ .d-inline-block= button_to 'generate', generate_newsvideo_path(@newsvideo), :data => { :confirm => 'Are you sure?' }
18
+
19
+ %i.fa.fa-compress.collapse-expand{ id: @newsvideo.id.to_s } Descr
20
+ .descr= raw @newsvideo.body.gsub(/(\r?\n){2}/, "<br /><br />")
12
21
  %br
13
22
  %br
14
23
 
15
24
  .NewsvideoTimeline
25
+
26
+ - tentative_duration_ms = @newsvideo.newspartials.map( &:duration_ms ).reduce( &:+ ) || 0
27
+ - px_per_ms = 0.1
28
+ .timeline-stamps{ style: "height: #{tentative_duration_ms*px_per_ms}px ;" }
29
+ - (0..tentative_duration_ms).step(500) do |t|
30
+ .tick{ style: "top: #{t * px_per_ms}px" }
31
+ = t
32
+
16
33
  - @newspartials.each do |newspartial|
17
34
  = render 'wco/newspartials/show_in_newsvideo', newspartial: newspartial
18
35
 
@@ -3,22 +3,26 @@
3
3
  = form_for profile do |f|
4
4
 
5
5
  .row
6
+ .col-6
7
+ .field
8
+ %label email
9
+ = f.text_field :email
6
10
 
7
- .field
8
- %label email
9
- = f.text_field :email
10
-
11
- .field
12
- %label name
13
- = f.text_field :name
11
+ .field
12
+ %label name
13
+ = f.text_field :name
14
14
 
15
- .field
16
- %label role
17
- = f.select :role, options_for_select(Wco::Profile.roles_list, selected: profile.role )
15
+ .field
16
+ %label leadset
17
+ = f.select :leadset, options_for_select(Wco::Leadset.list, selected: profile.leadset_id ), {}, { class: 'select2' }
18
18
 
19
- .field
20
- %label leadset
21
- = f.select :leadset, options_for_select(Wco::Leadset.list, selected: profile.leadset_id ), {}, { class: 'select2' }
19
+ .col-6
20
+ .field
21
+ %label role
22
+ = f.select :role, options_for_select(Wco::Profile.roles_list, selected: profile.role )
23
+ .field
24
+ %label descr
25
+ = f.text_area :descr
22
26
 
23
27
  %hr
24
28
  .row
@@ -71,6 +75,22 @@
71
75
  %label smtp_port
72
76
  = f.text_field :smtp_port
73
77
 
78
+ %hr
79
+ .row
80
+ .col-2
81
+ linkedin
82
+ .col-10
83
+ .field
84
+ %label linkedin_client_id
85
+ = f.text_field :linkedin_client_id
86
+
87
+ .field
88
+ %label linkedin_client_secret
89
+ = f.text_field :linkedin_client_secret
90
+
91
+ .field
92
+ %label linkedin_access_token
93
+ = f.text_field :linkedin_access_token
74
94
 
75
95
  .actions
76
96
  = f.submit 'Go'
@@ -0,0 +1,7 @@
1
+
2
+ .publishers--post-with
3
+ = form_tag run_any_publisher_path do
4
+ .d-flex
5
+ = select_tag :id, options_for_select(@publishers_list), class: 'select2'
6
+ = hidden_field_tag :props, props.to_json
7
+ = submit_tag 'Go', data: { confirm: 'Are you sure?' }
@@ -24,9 +24,18 @@
24
24
  -# = render '/wco/tags/index', tags: report.tags
25
25
  = f.select :tag_ids, options_for_select(@tags_list, selected: report.tag_ids), {}, { multiple: true, class: 'select2' }
26
26
 
27
+
27
28
  .field
28
- %label Newsvideo:
29
- = f.select :newsvideo_id, options_for_select(@newsvideos_list, selected: report.newsvideo_id), {}, {}
29
+ %label image
30
+ = f.file_field :image_thumb
31
+
32
+ - if report.image_thumb&.image?
33
+ %p Current:
34
+ = image_tag report.image_thumb.image.url(:thumb)
35
+
36
+ -# .field
37
+ -# %label Newsvideo:
38
+ -# = f.select :newsvideo_id, options_for_select(@newsvideos_list, selected: report.newsvideo_id), {}, {}
30
39
 
31
40
  .actions
32
41
  = f.submit
@@ -0,0 +1,23 @@
1
+
2
+
3
+ <script>
4
+ window.fbAsyncInit = function() {
5
+ FB.init({
6
+ appId : '61560755645186',
7
+ cookie : true,
8
+ xfbml : true,
9
+ version : 'v19.0'
10
+ });
11
+
12
+ FB.AppEvents.logPageView();
13
+
14
+ };
15
+
16
+ (function(d, s, id){
17
+ var js, fjs = d.getElementsByTagName(s)[0];
18
+ if (d.getElementById(id)) {return;}
19
+ js = d.createElement(s); js.id = id;
20
+ js.src = "https://connect.facebook.net/en_US/sdk.js";
21
+ fjs.parentNode.insertBefore(js, fjs);
22
+ }(document, 'script', 'facebook-jssdk'));
23
+ </script>
@@ -1,6 +1,8 @@
1
1
 
2
2
  - height_ms = 100.0/1000
3
3
 
4
+ = render 'wco/reports/to_facebook.html'
5
+
4
6
  .reports-show.maxwidth
5
7
  %h5
6
8
  = link_to '[~]', edit_report_path(@report)
@@ -11,8 +13,21 @@
11
13
 
12
14
  = render 'wco/tags/index_chips', tags: @report.tags
13
15
 
16
+ - if @report.image_thumb
17
+ = image_tag @report.image_thumb.photo.url(:thumb)
18
+
14
19
  .descr= raw @report.body
15
20
 
21
+ %hr
22
+ .actions
23
+ %ul
24
+ %li= button_to 'Post on Linkedin', report_to_linkedin_path(@report), data: { confirm: 'Are you sure?' }
25
+ %li= button_to 'Post on Facebook', report_to_facebook_path(@report), data: { confirm: 'Are you sure?' }
26
+ %li
27
+ .a
28
+ %label Post with a publisher
29
+ = render 'wco/publishers/post_with', props: { report_id: @report.id.to_s }
30
+
16
31
  -## this is in newspartials, newsvideos.
17
32
  -#
18
33
  .Timeline{ style: "height: #{@duration_ms*height_ms}px" }
@@ -16,11 +16,13 @@
16
16
  %th N Leads
17
17
 
18
18
  %th N Logs
19
+ %th N tags
19
20
  %tbody
20
21
  - tags.each do |tag|
21
22
  %tr
22
23
  %td
23
24
  = link_to '[~]', edit_tag_path(tag)
25
+ = button_to 'x', wco.tag_path(tag), method: :delete, data: { confirm: 'Are you sure?' }, form_class: 'd-inline-block'
24
26
  = link_to tag.slug, tag_path(tag)
25
27
  %td= tag.conversations.length
26
28
  %td= tag.message_stubs.length
@@ -30,4 +32,5 @@
30
32
  %td= tag.videos.length
31
33
  %td= tag.leadsets.length
32
34
  %td= tag.leads.length
33
- %td= tag.logs.length
35
+ %td= tag.logs.length
36
+ %td.text-center= tag.sons.length > 0 ? tag.sons.length : '-'
@@ -2,7 +2,8 @@
2
2
  %ul
3
3
  - nodes.each do |node|
4
4
  %li
5
- = link_to '[~]', wco.edit_tag_path(node[:tag][:id])
5
+ = link_to '[~]', wco.edit_tag_path(node[:tag][:id])
6
+ = button_to 'x', wco.tag_path(node[:tag][:id]), method: :delete, data: { confirm: 'Are you sure?' }, form_class: 'd-inline-block'
6
7
  = link_to node[:tag].slug, wco.tag_path(node[:tag][:id])
7
8
 
8
9
  - if node[:sons].present?
@@ -0,0 +1,9 @@
1
+
2
+ .tags-new-for-sidebar.maxwidth
3
+ .header
4
+ %h5.title New for sidebar
5
+
6
+ = form_tag wco.new_sidebar_tag_path do
7
+ = select_tag :tag_id, options_for_select(@tags_list), class: 'select2'
8
+ = submit_tag 'Go'
9
+