wco_models 3.1.0.37 → 3.1.0.38

Sign up to get free protection for your applications and to get access to all the features.
Files changed (182) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +3 -13
  3. data/app/assets/config/wco_models_manifest.js +2 -0
  4. data/app/assets/javascripts/wco/application.js +43 -5
  5. data/app/assets/javascripts/wco/collapse-expand.js +1 -0
  6. data/app/assets/javascripts/wco/file_upload.js +32 -0
  7. data/app/assets/javascripts/wco/shared.js +22 -0
  8. data/app/assets/stylesheets/wco/application.css +23 -8
  9. data/app/assets/stylesheets/wco/utils.scss +57 -1
  10. data/app/controllers/wco/application_controller.rb +9 -0
  11. data/app/controllers/wco/galleries_controller.rb +143 -0
  12. data/app/controllers/wco/headlines_controller.rb +71 -0
  13. data/app/controllers/wco/leads_controller.rb +59 -0
  14. data/app/controllers/wco/leadsets_controller.rb +90 -0
  15. data/app/controllers/wco/logs_controller.rb +64 -0
  16. data/app/controllers/wco/office_action_templates_controller.rb +80 -0
  17. data/app/controllers/wco/office_actions_controller.rb +71 -0
  18. data/app/controllers/wco/photos_controller.rb +78 -0
  19. data/app/controllers/wco/profiles_controller.rb +26 -0
  20. data/app/controllers/wco/publishers_controller.rb +60 -0
  21. data/app/controllers/wco/reports_controller.rb +75 -0
  22. data/app/controllers/wco/sites_controller.rb +52 -0
  23. data/app/controllers/wco/tags_controller.rb +57 -0
  24. data/app/helpers/wco/application_helper.rb +42 -0
  25. data/app/models/wco/asset.rb +26 -0
  26. data/app/models/wco/gallery.rb +3 -3
  27. data/app/models/wco/headline.rb +19 -0
  28. data/app/models/wco/invoice.rb +127 -0
  29. data/app/models/wco/lead.rb +42 -0
  30. data/app/models/wco/leadset.rb +8 -2
  31. data/app/models/wco/log.rb +18 -0
  32. data/app/models/wco/newsitem.rb +1 -0
  33. data/app/models/wco/office_action.rb +17 -18
  34. data/app/models/wco/office_action_template.rb +41 -0
  35. data/app/models/wco/office_action_template_tie.rb +20 -0
  36. data/app/models/wco/photo.rb +10 -8
  37. data/app/models/wco/price.rb +2 -0
  38. data/app/models/wco/product.rb +2 -0
  39. data/app/models/wco/profile.rb +1 -0
  40. data/app/models/wco/publisher.rb +68 -3
  41. data/app/models/wco/report.rb +48 -0
  42. data/app/models/wco/site.rb +12 -1
  43. data/app/models/wco/subscription.rb +1 -0
  44. data/app/models/wco/tag.rb +17 -4
  45. data/app/models/wco_email/campaign.rb +7 -11
  46. data/app/models/wco_email/context.rb +15 -14
  47. data/app/models/wco_email/conversation.rb +13 -27
  48. data/app/models/wco_email/{scheduled_email_action.rb → email_action.rb} +24 -20
  49. data/app/models/wco_email/email_action_template.rb +35 -0
  50. data/app/models/wco_email/email_filter.rb +9 -12
  51. data/app/models/wco_email/email_template.rb +124 -0
  52. data/app/models/wco_email/message.rb +228 -0
  53. data/app/models/wco_email/message_stub.rb +107 -0
  54. data/app/models/wco_email/obfuscated_redirect.rb +13 -0
  55. data/app/models/wco_email/unsubscribe.rb +19 -0
  56. data/app/models/wco_hosting/appliance.rb +1 -0
  57. data/app/models/wco_hosting/appliance_tmpl.rb +1 -0
  58. data/app/models/wco_hosting/domain.rb +1 -0
  59. data/app/models/wco_hosting/serverhost.rb +1 -0
  60. data/app/views/layouts/wco/application.haml +30 -17
  61. data/app/views/wco/_main_footer.haml +43 -0
  62. data/app/views/wco/_main_header.haml +37 -0
  63. data/app/views/wco/_main_header.haml-bk +109 -0
  64. data/app/views/wco/_paginate.haml +8 -0
  65. data/app/views/wco/_search.haml +8 -0
  66. data/app/views/wco/application/_debug.haml +0 -0
  67. data/app/views/wco/galleries/_form.haml +24 -0
  68. data/app/views/wco/galleries/_header.haml +8 -0
  69. data/app/views/wco/galleries/_index.haml +40 -0
  70. data/app/views/wco/galleries/_menu.haml-trash +10 -0
  71. data/app/views/wco/galleries/_menu_secondary.haml +12 -0
  72. data/app/views/wco/galleries/_thumbs.haml +9 -0
  73. data/app/views/wco/galleries/_title.haml +16 -0
  74. data/app/views/wco/galleries/edit.haml +6 -0
  75. data/app/views/wco/galleries/new.haml +6 -0
  76. data/app/views/wco/galleries/show.haml +43 -0
  77. data/app/views/wco/headlines/_form.haml +17 -0
  78. data/app/views/wco/headlines/_header.haml +6 -0
  79. data/app/views/wco/headlines/_index.haml +20 -0
  80. data/app/views/wco/headlines/edit.haml +6 -0
  81. data/app/views/wco/headlines/new.haml +2 -0
  82. data/app/views/wco/invoices/_form.haml-trash +29 -0
  83. data/app/views/wco/invoices/_header.haml +6 -0
  84. data/app/views/wco/invoices/_index_list.haml +13 -0
  85. data/app/views/wco/invoices/_index_table.haml +20 -0
  86. data/app/views/wco/invoices/index.haml +3 -0
  87. data/app/views/wco/invoices/new_pdf.haml +18 -0
  88. data/app/views/wco/invoices/new_stripe.haml +50 -0
  89. data/app/views/wco/invoices/show.haml +23 -0
  90. data/app/views/wco/kaminari/_first_page.html.erb +11 -0
  91. data/app/views/wco/kaminari/_gap.html.erb +8 -0
  92. data/app/views/wco/kaminari/_last_page.html.erb +11 -0
  93. data/app/views/wco/kaminari/_next_page.html.erb +11 -0
  94. data/app/views/wco/kaminari/_page.html.erb +13 -0
  95. data/app/views/wco/kaminari/_paginator.html.erb +25 -0
  96. data/app/views/wco/kaminari/_prev_page.html.erb +11 -0
  97. data/app/views/wco/leads/_form.haml +45 -0
  98. data/app/views/wco/leads/_form_import.haml +11 -0
  99. data/app/views/wco/leads/_header.haml +7 -0
  100. data/app/views/wco/leads/_index.haml +75 -0
  101. data/app/views/wco/leads/_index_rows.haml +11 -0
  102. data/app/views/wco/leads/edit.haml +22 -0
  103. data/app/views/wco/leads/index.haml +7 -0
  104. data/app/views/wco/leads/new.haml +9 -0
  105. data/app/views/wco/leads/show.haml +85 -0
  106. data/app/views/wco/leadsets/_form.haml +28 -0
  107. data/app/views/wco/leadsets/_header.haml +6 -0
  108. data/app/views/wco/leadsets/edit.haml +4 -0
  109. data/app/views/wco/leadsets/index.haml +45 -0
  110. data/app/views/wco/leadsets/index_dataTables.haml +33 -0
  111. data/app/views/wco/leadsets/new.haml +6 -0
  112. data/app/views/wco/leadsets/show.haml +52 -0
  113. data/app/views/wco/logs/_form.haml +17 -0
  114. data/app/views/wco/logs/_header.haml +6 -0
  115. data/app/views/wco/logs/_index.haml +23 -0
  116. data/app/views/wco/logs/edit.haml +6 -0
  117. data/app/views/wco/logs/new.haml +2 -0
  118. data/app/views/wco/office_action_templates/_form.haml +46 -0
  119. data/app/views/wco/office_action_templates/_header.haml +8 -0
  120. data/app/views/wco/office_action_templates/_ties.haml +18 -0
  121. data/app/views/wco/office_action_templates/edit.haml +6 -0
  122. data/app/views/wco/office_action_templates/index.haml +17 -0
  123. data/app/views/wco/office_action_templates/new.haml +5 -0
  124. data/app/views/wco/office_action_templates/show.haml +22 -0
  125. data/app/views/wco/office_actions/_form.haml +22 -0
  126. data/app/views/wco/office_actions/_header.haml +6 -0
  127. data/app/views/wco/office_actions/_index.haml +15 -0
  128. data/app/views/wco/office_actions/edit.haml +5 -0
  129. data/app/views/wco/office_actions/index.haml +10 -0
  130. data/app/views/wco/office_actions/new.haml +4 -0
  131. data/app/views/wco/office_actions/show.haml +5 -0
  132. data/app/views/wco/photos/_form.haml +0 -0
  133. data/app/views/wco/photos/_index_thumbs.haml +7 -0
  134. data/app/views/wco/photos/_meta.haml +7 -0
  135. data/app/views/wco/photos/_meta_manager.haml +7 -0
  136. data/app/views/wco/photos/_multinew.haml +6 -0
  137. data/app/views/wco/photos/index.haml +3 -0
  138. data/app/views/wco/photos/new.haml +0 -0
  139. data/app/views/wco/photos/show.haml +6 -0
  140. data/app/views/wco/photos/without_gallery.haml +11 -0
  141. data/app/views/wco/prices/_form.haml +1 -1
  142. data/app/views/wco/products/_header.haml +6 -0
  143. data/app/views/wco/publishers/_form.haml +28 -0
  144. data/app/views/wco/publishers/_header.haml +6 -0
  145. data/app/views/wco/publishers/edit.haml +4 -0
  146. data/app/views/wco/publishers/index.haml +37 -0
  147. data/app/views/wco/publishers/new.haml +4 -0
  148. data/app/views/wco/reports/_form.haml +28 -0
  149. data/app/views/wco/reports/_header.haml +14 -0
  150. data/app/views/wco/reports/edit.haml +4 -0
  151. data/app/views/wco/reports/index.haml +17 -0
  152. data/app/views/wco/reports/index_table.haml +17 -0
  153. data/app/views/wco/reports/new.haml +4 -0
  154. data/app/views/wco/reports/show.haml +8 -0
  155. data/app/views/wco/sites/_form.haml +21 -0
  156. data/app/views/wco/sites/_header.haml +6 -0
  157. data/app/views/wco/sites/edit.haml +4 -0
  158. data/app/views/wco/sites/index.haml +24 -0
  159. data/app/views/wco/sites/new.haml +4 -0
  160. data/app/views/wco/tags/_form.haml +10 -0
  161. data/app/views/wco/tags/_header.haml +6 -0
  162. data/app/views/wco/tags/_index.haml +10 -0
  163. data/app/views/wco/tags/_index_inline.haml +8 -0
  164. data/app/views/wco/tags/edit.haml +0 -0
  165. data/app/views/wco/tags/index.haml +9 -0
  166. data/app/views/wco/tags/new.haml +0 -0
  167. data/app/views/wco/tags/show.haml +15 -0
  168. data/config/routes.rb +42 -0
  169. data/lib/tasks/db_tasks.rake +13 -0
  170. data/lib/tasks/office_tasks.rake +36 -0
  171. data/lib/tasks/scrape_tasks.rake-trash +22 -0
  172. data/lib/wco/ai_writer.rb +55 -0
  173. data/lib/wco/engine.rb +0 -1
  174. data/lib/wco/office_worker.rb +4 -0
  175. data/lib/wco/scrape_wsj.rb +29 -0
  176. data/lib/wco/scrape_wsj_capy.rb +44 -0
  177. data/lib/wco_models.rb +15 -2
  178. metadata +241 -46
  179. data/app/helpers/ish_models/application_helper.rb +0 -4
  180. data/app/models/wco_email/message_template.rb +0 -6
  181. data/lib/tasks/ish_models_tasks.rake +0 -4
  182. /data/app/views/wco/{application/_alerts_notices.haml → _alerts_notices.haml} +0 -0
@@ -0,0 +1,127 @@
1
+ require 'autoinc'
2
+ require 'prawn'
3
+ require 'prawn/table'
4
+
5
+ ##
6
+ ## Invoice - for wasya.co
7
+ ## 2017-10-31 _vp_ Start
8
+ ## 2023-08-18 _vp_ Continue
9
+ ##
10
+ class Wco::Invoice
11
+ include Mongoid::Document
12
+ include Mongoid::Timestamps
13
+ include Mongoid::Autoinc
14
+ include Mongoid::Paranoia
15
+ store_in collection: 'ish_invoice'
16
+
17
+ field :email, type: String
18
+
19
+ field :invoice_id, type: String # stripe
20
+
21
+ belongs_to :leadset, class_name: 'Wco::Leadset'
22
+
23
+ field :number, type: Integer
24
+
25
+ field :month_on, type: Date
26
+
27
+ has_one :asset, class_name: 'Wco::Asset' ## the pdf
28
+
29
+ def filename
30
+ "invoice-#{number}.pdf"
31
+ end
32
+
33
+ # field :amount_cents, type: Integer
34
+
35
+ field :description, type: String
36
+ field :items, type: Array # used by stripe
37
+
38
+
39
+
40
+ ## Prawn/pdf unit of measure is 1/72"
41
+ ## Canvas width: 612, height: 792
42
+ ##
43
+ ## tree image: 896 x 1159
44
+ ## tree image: 791 x 1024
45
+ ## tree image: 964 x 1248
46
+ ##
47
+ def generate_monthly_invoice
48
+ tree_img_url = "#{Rails.root.join('public')}/tree-#{number}.jpg"
49
+ wasya_co_logo_url = "#{Rails.root.join('public')}/259x66-WasyaCo-logo.png"
50
+
51
+ ## canvas width: 612, height: 792
52
+ pdf = Prawn::Document.new
53
+
54
+ pdf.canvas do
55
+ pdf.image tree_img_url, at: [ 0, 792 ], width: 612
56
+
57
+ pdf.fill_color 'ffffff'
58
+ pdf.transparent( 0.75 ) do
59
+ pdf.fill_rectangle [0, 792], 612, 792
60
+ end
61
+ pdf.fill_color '000000'
62
+
63
+ pdf.image wasya_co_logo_url, at: [252, 720], width: 108 ## 1.5"
64
+
65
+ pdf.bounding_box( [0.75*72, 9.25*72], width: 3.25*72, height: 0.75*72 ) do
66
+ pdf.text "From:"
67
+ pdf.text "Wasya Co"
68
+ pdf.text "victor@wasya.co"
69
+ end
70
+
71
+ pdf.bounding_box( [4.5*72, 9.25*72], width: 3.25*72, height: 0.75*72 ) do
72
+ pdf.text "Stats:"
73
+ pdf.text "Date: #{ Time.now.to_date.to_s }"
74
+ pdf.text "Invoice #: #{ number }"
75
+ end
76
+
77
+ pdf.bounding_box( [0.75*72, 8.25*72], width: 3.25*72, height: 0.75*72 ) do
78
+ pdf.text "To:"
79
+ pdf.text leadset.name
80
+ pdf.text leadset.email
81
+ end
82
+
83
+ pdf.bounding_box( [4.5*72, 8.25*72], width: 3.25*72, height: 0.75*72 ) do
84
+ pdf.text "Notes:"
85
+ pdf.text "Support & various tasks, for the month of #{ month_on.strftime('%B') }."
86
+ end
87
+
88
+ lineitems_with_header = [
89
+ [ 'Description', 'Per Unit', '# of Units', 'Subtotal' ]
90
+ ]
91
+ total = 0
92
+ leadset.subscriptions.each do |i|
93
+ subtotal = (i.price.amount_cents * i.quantity).to_f/100
94
+ lineitems_with_header.push([ i.price.product.name, i.price.name_simple, i.quantity, subtotal ])
95
+ total += subtotal
96
+ end
97
+
98
+
99
+ pdf.move_down 20
100
+ pdf.table(lineitems_with_header, {
101
+ position: :center,
102
+ width: 7.5*72,
103
+ cell_style: {
104
+ inline_format: true,
105
+ borders: [ :bottom ]
106
+ },
107
+ } )
108
+
109
+ pdf.table([
110
+ [ 'Total' ],
111
+ [ total ],
112
+ ], {
113
+ position: 7*72,
114
+ width: 1*72,
115
+ cell_style: {
116
+ inline_format: true,
117
+ borders: [ :bottom ]
118
+ },
119
+ } )
120
+
121
+ pdf.text_box "Thank you!", at: [ 3.25*72, 1.25*72 ], width: 2*72, height: 1*72, align: :center
122
+ end
123
+
124
+ return pdf
125
+ end
126
+
127
+ end
@@ -2,6 +2,48 @@
2
2
  class Wco::Lead
3
3
  include Mongoid::Document
4
4
  include Mongoid::Timestamps
5
+ include Mongoid::Paranoia
5
6
  store_in collection: 'wco_leads'
6
7
 
8
+ field :email
9
+ validates :email, presence: true, uniqueness: true
10
+ index({ email: -1 })
11
+
12
+ field :name
13
+ field :phone
14
+ field :address
15
+
16
+ belongs_to :leadset, class_name: 'Wco::Leadset'
17
+ has_one :photo, class_name: 'Wco::Photo'
18
+
19
+ has_and_belongs_to_many :conversations, class_name: '::WcoEmail::Conversation'
20
+ def convs; conversations; end
21
+ has_many :email_contexts, class_name: '::WcoEmail::Context'
22
+ def ctxs; email_contexts; end
23
+ has_many :email_actions, class_name: '::WcoEmail::EmailAction'
24
+ # has_and_belongs_to_many :scheduled_email_actions, class_name: '::WcoEmail::ScheduledEmailAction'
25
+ def schs; email_actions; end
26
+ has_and_belongs_to_many :email_campaigns, class_name: '::WcoEmail::Campaign'
27
+ has_and_belongs_to_many :tags, class_name: '::Wco::Tag'
28
+
29
+ # has_many :galleries, class_name: 'Wco::Gallery'
30
+ # has_many :videos, class_name: 'Wco::Video'
31
+
32
+ def self.list
33
+ all.map { |p| [ p.id, p.email ] }
34
+ end
35
+
36
+ OP_DELETE = 'delete'
37
+ OP_ADD_TO_CAMPAIGN = 'add_to_campaign'
38
+ OPS = [ OP_DELETE, OP_ADD_TO_CAMPAIGN ]
39
+
40
+ has_many :unsubscribes, class_name: '::WcoEmail::Unsubscribe'
41
+ field :unsubscribe_token
42
+ def unsubscribe_token
43
+ if !self[:unsubscribe_token]
44
+ update_attributes({ unsubscribe_token: (0...8).map { (65 + rand(26)).chr }.join })
45
+ end
46
+ self[:unsubscribe_token]
47
+ end
48
+
7
49
  end
@@ -2,19 +2,25 @@
2
2
  class Wco::Leadset
3
3
  include Mongoid::Document
4
4
  include Mongoid::Timestamps
5
+ include Mongoid::Paranoia
5
6
  store_in collection: 'wco_leadsets'
6
7
 
7
- field :company_url
8
+ field :company_url
8
9
  validates :company_url, presence: true, uniqueness: true
9
10
  index({ company_url: 1 }, { name: 'company_url' })
10
11
 
11
12
  field :email
12
13
  index({ email: 1 }, { name: 'email' })
13
- validates :email, presence: true # , uniqueness: true ## @TODO: should it be unique? _vp_ 2023-12-22
14
+ validates :email, uniqueness: { allow_nil: true } # presence: true
14
15
 
16
+ has_many :leads, class_name: 'Wco::Lead'
15
17
  has_many :profiles, class_name: 'Wco::Profile', inverse_of: :leadset
16
18
  has_many :appliances, class_name: 'WcoHosting::Appliance', inverse_of: :leadset
17
19
  has_many :subscriptions, class_name: 'Wco::Subscription', inverse_of: :leadset
20
+ has_and_belongs_to_many :tags, class_name: 'Wco::Tag'
21
+
22
+ has_many :invoices, class_name: 'Wco::Invoice'
23
+ field :next_invoice_number, type: :integer, default: 100
18
24
 
19
25
  has_and_belongs_to_many :serverhosts, class_name: 'WcoHosting::Serverhost' # , inverse_of: :leadset
20
26
  def next_serverhost
@@ -0,0 +1,18 @@
1
+
2
+
3
+ class Wco::Log
4
+ include Mongoid::Document
5
+ include Mongoid::Timestamps
6
+ include Mongoid::Paranoia
7
+ store_in collection: 'wco_logs'
8
+
9
+ field :message
10
+
11
+ field :class_name
12
+ field :object_id
13
+
14
+ field :raw_json, type: Object, default: '{}'
15
+
16
+ has_and_belongs_to_many :tags
17
+
18
+ end
@@ -3,6 +3,7 @@
3
3
  class Wco::Newsitem
4
4
  include Mongoid::Document
5
5
  include Mongoid::Timestamps
6
+ include Mongoid::Paranoia
6
7
  store_in collection: 'wco_newsitems'
7
8
 
8
9
  belongs_to :profile, class_name: 'Wco::Profile', optional: true
@@ -1,32 +1,31 @@
1
1
 
2
- ##
3
- ## 2023-09-13 _vp_ I don't know if it's even used.
4
- ##
5
2
  class Wco::OfficeAction
6
3
  include Mongoid::Document
7
4
  include Mongoid::Timestamps
8
- store_in collection: 'office_actions'
5
+ include Mongoid::Paranoia
6
+ store_in collection: 'wco_office_actions'
9
7
 
10
8
  field :slug, type: :string
11
9
  validates :slug, uniqueness: true, allow_nil: true
12
10
 
13
- field :descr, type: :string ## optional
11
+ # field :descr, type: :string ## optional
14
12
 
13
+ belongs_to :office_action_template, inverse_of: :office_action
14
+ def tmpl
15
+ office_action_template
16
+ end
15
17
 
16
- STATE_ACTIVE = 'active'
17
- STATE_INACTIVE = 'inactive'
18
- STATES = [ STATE_ACTIVE, STATE_INACTIVE ]
19
- field :state, type: :string
20
- scope :active, ->{ where( state: STATE_ACTIVE ) }
21
-
22
-
23
- has_many :ties, class_name: '::Office::ActionTie', inverse_of: :office_action
24
- has_many :prev_ties, class_name: '::Office::ActionTie', inverse_of: :next_office_action
25
- accepts_nested_attributes_for :ties
26
-
27
- field :action_exe, type: :string
18
+ STATUS_ACTIVE = 'active'
19
+ STATUS_INACTIVE = 'inactive'
20
+ STATUSS = [ STATUS_ACTIVE, STATUS_INACTIVE ]
21
+ field :status, type: :string
22
+ scope :active, ->{ where( status: STATUS_ACTIVE ) }
28
23
 
29
24
  field :perform_at, type: :time
30
25
 
26
+ def to_s
27
+ slug
28
+ end
29
+
31
30
  end
32
- OAct = Wco::OfficeAction
31
+
@@ -0,0 +1,41 @@
1
+
2
+ require 'wco/ai_writer'
3
+
4
+ ##
5
+ ## A Publisher is an OAT
6
+ ##
7
+ class Wco::OfficeActionTemplate
8
+ include Mongoid::Document
9
+ include Mongoid::Timestamps
10
+ include Mongoid::Paranoia
11
+ store_in collection: 'wco_office_action_templates'
12
+
13
+ field :slug
14
+ validates :slug, presence: true, uniqueness: true
15
+
16
+ belongs_to :from, polymorphic: true, optional: true
17
+ belongs_to :publisher, class_name: 'Wco::Publisher', optional: true
18
+
19
+ field :action_exe, type: :string
20
+ validates :action_exe, presence: true
21
+ def do_run
22
+ eval( action_exe )
23
+ end
24
+
25
+ has_many :office_actions, inverse_of: :office_action_template
26
+ def actions; office_actions; end
27
+
28
+ has_many :ties, class_name: 'OfficeActionTemplateTie', inverse_of: :office_action_template
29
+ has_many :prev_ties, class_name: 'OfficeActionTemplateTie', inverse_of: :next_office_action_template
30
+ accepts_nested_attributes_for :ties
31
+
32
+ def to_s
33
+ "#{slug}"
34
+ end
35
+
36
+ def self.list
37
+ [[nil,nil]] + all.map { |ttt| [ ttt.slug, ttt.id ] }
38
+ end
39
+
40
+ end
41
+ OAT = Wco::OfficeActionTemplate
@@ -0,0 +1,20 @@
1
+
2
+ class Wco::OfficeActionTemplateTie
3
+ include Mongoid::Document
4
+ include Mongoid::Timestamps
5
+ store_in collection: 'wco_office_action_template_ties'
6
+
7
+ attr_accessor :to_delete
8
+
9
+ belongs_to :office_action_template, class_name: 'OfficeActionTemplate', inverse_of: :ties
10
+ def oat; office_action_template; end
11
+
12
+ belongs_to :next_office_action_template, class_name: 'OfficeActionTemplate', inverse_of: :prev_ties
13
+ def next_oat; next_office_action_template; end
14
+ # def tmpl; next_office_action_template; end
15
+
16
+
17
+ field :next_at_exe, type: :string
18
+ validates :next_at_exe, presence: true
19
+
20
+ end
@@ -6,19 +6,21 @@ class Wco::Photo
6
6
  include Mongoid::Document
7
7
  include Mongoid::Timestamps
8
8
  include Mongoid::Paperclip
9
+ include Mongoid::Paranoia
9
10
  include Wco::Utils
11
+ store_in collection: 'wco_photos'
10
12
 
11
- # belongs_to :email_message, :optional => true, :class_name => 'Office::EmailMessage'
12
- # belongs_to :report, :optional => true
13
- belongs_to :gallery, class_name: 'Wco::Gallery', :optional => true
13
+ belongs_to :email_message, class_name: 'WcoEmail::Message', optional: true
14
+ belongs_to :gallery, class_name: 'Wco::Gallery', optional: true
15
+ belongs_to :lead, class_name: 'Wco::Lead', optional: true
14
16
  # belongs_to :newsitem, :optional => true
15
17
 
16
- # photo.photo.to_s.split('/').last.split('?').first
17
- field :name, :type => String
18
+ field :name
18
19
  def name
19
- return self[:name] if self[:name]
20
- update_attribute(:name, self.photo.to_s.split('/').last.split('?').first)
21
- name
20
+ if !self[:name]
21
+ update_attribute(:name, self.photo.to_s.split('/').last.split('?').first)
22
+ end
23
+ self[:name]
22
24
  end
23
25
 
24
26
  field :ordering, type: :integer
@@ -2,6 +2,8 @@
2
2
  class Wco::Price
3
3
  include Mongoid::Document
4
4
  include Mongoid::Timestamps
5
+ include Mongoid::Paranoia
6
+ store_in collection: 'wco_prices'
5
7
 
6
8
  # belongs_to :product, class_name: 'Wco::Product', inverse_of: :prices
7
9
  ## Wco::Product, WcoHosting::ApplianceTmpl:
@@ -2,6 +2,8 @@
2
2
  class Wco::Product
3
3
  include Mongoid::Document
4
4
  include Mongoid::Timestamps
5
+ include Mongoid::Paranoia
6
+ store_in collection: 'wco_products'
5
7
 
6
8
  field :name
7
9
 
@@ -2,6 +2,7 @@
2
2
  class Wco::Profile
3
3
  include Mongoid::Document
4
4
  include Mongoid::Timestamps
5
+ include Mongoid::Paranoia
5
6
  store_in collection: 'ish_user_profiles'
6
7
 
7
8
  field :email
@@ -2,21 +2,86 @@
2
2
  class Wco::Publisher
3
3
  include Mongoid::Document
4
4
  include Mongoid::Timestamps
5
+ include Mongoid::Paranoia
5
6
  store_in collection: 'wco_publishers'
6
7
 
7
- field :name
8
+ field :slug
9
+ validates :slug, presence: true, uniqueness: true
8
10
 
9
11
  KIND_ARTICLE = 'article'
10
12
  KIND_IMAGE = 'image'
11
13
  field :kind, type: :string
12
14
 
13
- belongs_to :to_site, class_name: 'Wco::Site'
14
-
15
+ belongs_to :site, class_name: 'Wco::Site'
15
16
 
16
17
  field :context_eval
18
+ field :after_eval
17
19
  field :post_body_tmpl
18
20
 
21
+ has_many :oats, class_name: 'Wco::OfficeActionTemplate'
22
+
23
+ ## @TODO: move to PublisherDrupal
24
+ def do_run
25
+ @report = report
26
+
27
+ @ctx = OpenStruct.new
28
+ eval( context_eval )
29
+ puts! @ctx, '@ctx'
30
+
31
+ tmpl = ERB.new post_body_tmpl
32
+ body = JSON.parse tmpl.result(binding)
33
+ puts! body, 'body'
34
+
35
+ headers = {}
36
+ if Wco::Site::KIND_DRUPAL == site.kind
37
+ headers['Content-Type'] = 'application/hal+json'
38
+ end
39
+
40
+ out = Wco::HTTParty.post( "#{site.origin}#{site.post_path}", {
41
+ body: body.to_json,
42
+ headers: headers,
43
+ basic_auth: { username: site.username, password: site.password },
44
+ })
45
+ puts! out.response, 'out'
46
+
47
+ eval( after_eval )
48
+ end
49
+
50
+ def publish_report report
51
+ @report = report
52
+ @site = site
53
+
54
+ @ctx = OpenStruct.new
55
+ eval( context_eval )
56
+ puts! @ctx, '@ctx'
57
+
58
+
59
+ tmpl = ERB.new post_body_tmpl
60
+ body = JSON.parse tmpl.result(binding)
61
+ puts! body, 'body'
62
+
63
+ headers = {}
64
+ if Wco::Site::KIND_DRUPAL == site.kind
65
+ headers['Content-Type'] = 'application/hal+json'
66
+ end
67
+
68
+ out = Wco::HTTParty.post( "#{site.origin}#{site.post_path}", {
69
+ body: body.to_json,
70
+ headers: headers,
71
+ basic_auth: { username: site.username, password: site.password },
72
+ })
73
+ puts! out.response, 'out'
74
+
75
+ eval( after_eval )
76
+ end
77
+
78
+ def to_s
79
+ "#{slug}: #{kind} => #{site}"
80
+ end
19
81
 
82
+ def self.list
83
+ [[nil,nil]] + all.map { |p| [p, p.id] }
84
+ end
20
85
 
21
86
  end
22
87
 
@@ -0,0 +1,48 @@
1
+
2
+ ##
3
+ ##
4
+ ##
5
+ # @report.body.split("\n\n").map { |ttt| "<p>#{ttt}</p>" }.join
6
+ #
7
+ class Wco::Report
8
+ include Mongoid::Document
9
+ include Mongoid::Timestamps
10
+ include Mongoid::Paranoia
11
+ include Wco::Utils
12
+ store_in collection: 'wco_reports'
13
+
14
+ field :title
15
+ validates :title, presence: true, uniqueness: true
16
+ index({ title: 1 }, { unique: true })
17
+
18
+ field :subtitle
19
+
20
+ field :slug
21
+ validates :slug, presence: true, uniqueness: true
22
+ index({ :slug => 1 }, { :unique => true })
23
+ before_validation :set_slug, :on => :create
24
+
25
+ field :body
26
+
27
+ # field :raw_json, type: :object, default: '{}'
28
+
29
+ # field :is_trash, :type => Boolean, :default => false
30
+ # index({ :is_trash => 1, :is_public => 1 })
31
+
32
+ # field :is_public, :type => Boolean, :default => true
33
+ # index({ :is_public => 1 })
34
+ # scope :public, ->{ where({ is_public: true }) }
35
+
36
+ field :x, :type => Float
37
+ field :y, :type => Float
38
+ field :z, :type => Float
39
+
40
+ # has_one :photo
41
+
42
+ def export_fields
43
+ %w| name descr |
44
+ end
45
+
46
+ has_and_belongs_to_many :tags
47
+
48
+ end
@@ -2,6 +2,7 @@
2
2
  class Wco::Site
3
3
  include Mongoid::Document
4
4
  include Mongoid::Timestamps
5
+ include Mongoid::Paranoia
5
6
  store_in collection: 'wco_sites'
6
7
 
7
8
  KIND_DRUPAL = 'drupal'
@@ -13,13 +14,23 @@ class Wco::Site
13
14
  [nil] + KINDS
14
15
  end
15
16
 
16
- has_many :publishers, class_name: 'Wco::Publisher'
17
+ has_many :publishers # , class_name: 'Wco::Publisher'
18
+ has_many :headlines # , class_name: 'Wco::Newstitle'
19
+
20
+ field :slug
21
+ validates :slug, presence: true, uniqueness: true
17
22
 
18
23
  field :origin # http://pi.local
24
+ validates :origin, presence: true, uniqueness: true
25
+
19
26
  field :post_path # /node?_format=hal_json
20
27
  field :username
21
28
  field :password
22
29
 
30
+ def to_s
31
+ origin
32
+ end
33
+
23
34
  def self.list
24
35
  [[nil,nil]] + all.map { |s| [ s.origin, s.id ] }
25
36
  end
@@ -2,6 +2,7 @@
2
2
  class Wco::Subscription
3
3
  include Mongoid::Document
4
4
  include Mongoid::Timestamps
5
+ include Mongoid::Paranoia
5
6
  store_in collection: 'wco_subscriptions'
6
7
 
7
8
  belongs_to :product, polymorphic: true # includes: Wco::Product , WcoHosting::ApplianceTmpl
@@ -2,15 +2,28 @@
2
2
  class Wco::Tag
3
3
  include Mongoid::Document
4
4
  include Mongoid::Timestamps
5
+ include Mongoid::Paranoia
5
6
  store_in collection: 'wco_tags'
6
7
 
7
8
  field :slug
8
- # index
9
- # validate presence
10
- # validate uniqueness ?
9
+ validates :slug, presence: true, uniqueness: true
10
+ index({ slug: -1 })
11
11
 
12
12
  # parent-child
13
13
 
14
- has_and_belongs_to_many :email_conversations, class_name: 'WcoEmail::Conversation'
14
+ has_and_belongs_to_many :conversations, class_name: 'WcoEmail::Conversation'
15
+ has_and_belongs_to_many :message_stubs, class_name: 'WcoEmail::MessageStub'
16
+ has_and_belongs_to_many :headlines # , class_name: 'Headline'
17
+ has_and_belongs_to_many :leads # , class_name: 'Lead'
18
+ has_and_belongs_to_many :leadsets # , class_name: 'Leadset'
19
+ has_and_belongs_to_many :reports
20
+ has_and_belongs_to_many :logs
21
+
22
+ INBOX = 'inbox'
23
+ TRASH = 'trash'
24
+
25
+ def self.list
26
+ [[nil,nil]] + all.map { |p| [ p.slug, p.id ] }
27
+ end
15
28
 
16
29
  end
@@ -6,6 +6,7 @@
6
6
  class WcoEmail::Campaign
7
7
  include Mongoid::Document
8
8
  include Mongoid::Timestamps
9
+ include Mongoid::Paranoia
9
10
  store_in collection: 'ish_email_campaigns'
10
11
 
11
12
  field :slug
@@ -25,19 +26,10 @@ class WcoEmail::Campaign
25
26
  field :sent_at, type: DateTime
26
27
  field :send_at, type: DateTime
27
28
 
28
- has_many :unsubscribes, class_name: '::Ish::EmailUnsubscribe', inverse_of: :campaign
29
+ has_many :unsubscribes, class_name: 'WcoEmail::Unsubscribe', inverse_of: :campaign
30
+ has_and_belongs_to_many :leads, class_name: 'Wco::Lead'
29
31
 
30
- def campaign_leads
31
- return ::EmailCampaignLead.where( email_campaign_id: self.id.to_s ).includes( :lead )
32
- end
33
-
34
- def leads
35
- ::Lead.joins( :email_campaign_leads ).where( 'email_campaign_leads.email_campaign_id' => self.id.to_s )
36
- end
37
-
38
- ##
39
32
  ## For tracking
40
- ##
41
33
  attr_reader :tid
42
34
 
43
35
  def do_send
@@ -52,4 +44,8 @@ class WcoEmail::Campaign
52
44
  end
53
45
  end
54
46
 
47
+ def self.list
48
+ [[nil,nil]] + all.map { |p| [ p.slug, p.id ] }
49
+ end
50
+
55
51
  end