tomify 0.1.0 → 0.1.1

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 (43) hide show
  1. checksums.yaml +4 -4
  2. data/app/assets/javascripts/tomify/dynamic/classes/form.coffee +1 -0
  3. data/app/assets/javascripts/tomify/dynamic/classes/model.coffee +1 -0
  4. data/app/assets/javascripts/tomify/dynamic/react/components/admin/feedback.coffee +20 -0
  5. data/app/assets/javascripts/tomify/dynamic/react/components/admin/pages.coffee.erb +3 -4
  6. data/app/assets/javascripts/tomify/dynamic/react/components/admin/settings.coffee +2 -2
  7. data/app/assets/javascripts/tomify/dynamic/react/components/admin/sidebars.coffee.erb +2 -2
  8. data/app/assets/javascripts/tomify/dynamic/react/components/admin/uploads.coffee +2 -2
  9. data/app/assets/javascripts/tomify/dynamic/react/components/admin/users.coffee +2 -2
  10. data/app/assets/javascripts/tomify/dynamic/react/components/index.coffee +39 -30
  11. data/app/assets/javascripts/tomify/dynamic/react/components/layout/public_navbar.coffee +2 -2
  12. data/app/assets/javascripts/tomify/dynamic/react/components/public/feedback.coffee +39 -0
  13. data/app/assets/javascripts/tomify/dynamic/react/components/public/subscription.coffee +1 -1
  14. data/app/assets/javascripts/tomify/dynamic/react/components/show.coffee +60 -0
  15. data/app/controllers/tomify/admin/feedback_controller.rb +2 -0
  16. data/app/controllers/tomify/api/admin/feedback_controller.rb +16 -0
  17. data/app/controllers/tomify/api/admin/pages_controller.rb +1 -0
  18. data/app/controllers/tomify/api/admin/settings_controller.rb +1 -0
  19. data/app/controllers/tomify/api/admin/sidebars_controller.rb +1 -0
  20. data/app/controllers/tomify/api/admin/uploads_controller.rb +1 -0
  21. data/app/controllers/tomify/api/public/feedback_controller.rb +15 -0
  22. data/app/controllers/tomify/concerns/default/navbar_helper.rb +1 -0
  23. data/app/controllers/tomify/public/feedback_controller.rb +5 -0
  24. data/app/mailers/tomify/feedback_mailer.rb +13 -0
  25. data/app/models/tomify/concerns/feedback.rb +23 -0
  26. data/app/models/tomify/concerns/page.rb +1 -1
  27. data/app/models/tomify/feedback.rb +3 -0
  28. data/app/models/tomify/setting.rb +1 -1
  29. data/app/views/templates/feedback.haml +1 -0
  30. data/app/views/tomify/mailers/feedback_mailer/admin.haml +17 -0
  31. data/app/views/tomify/mailers/feedback_mailer/user.haml +8 -0
  32. data/app/views/tomify/mailers/partials/_unsubscribe.haml +3 -2
  33. data/app/views/tomify/mailers/user_mailer/invite.haml +2 -2
  34. data/app/views/tomify/mailers/user_mailer/reset_password.haml +5 -5
  35. data/app/views/tomify/mailers/user_mailer/welcome.haml +2 -2
  36. data/config/initializers/inflectors.rb +3 -0
  37. data/config/routes.rb +3 -0
  38. data/db/migrate/19900000000012_create_feedback.rb +15 -0
  39. data/db/seeds.rb +1 -1
  40. data/lib/previews/tomify/feedback_preview.rb +14 -0
  41. data/lib/tomify/version.rb +1 -1
  42. data/lib/tomify.rb +3 -0
  43. metadata +18 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: d7adedc7c0800596d7cb43f4fa62d73f062c60de
4
- data.tar.gz: 22f4e06750d3eff48a100d576de05fc0c6f36368
3
+ metadata.gz: 57007dacbc53ef0792f799a4dd59ddc0f1fbd1aa
4
+ data.tar.gz: c599f317a3bd1b022c2b6d3e1a5b108e5abb14a1
5
5
  SHA512:
6
- metadata.gz: 4f317a362b20c86647022e24a3bec525f70ff0b724c84df451d1d723d1de61a80e3e92fcb349fa2c2731bfbb8812f203865cd2a25e2fabc3188b531ba2d47651
7
- data.tar.gz: ac43203ca348e0da245ed209dba4c2520adbe84c29f988dc5e207cccb4f94406cd43e9a2996c758946d34292c328b0b8ef2df4a5bf46788ad5924d6a10628bc3
6
+ metadata.gz: 219e26d3ce04cf98995c401ac4264f90932d316080ea2a4cec2427bbfb793302478087037f0c6731129e3cd2cb117ebf0eeb0003156d55803336ec3d7a258c25
7
+ data.tar.gz: 931fcab4e391dcf69120fa1cbc71d2e460687388cc6be7f13e930f923f9ed6a4b1a29d24f8263b23437394db93081fd7f802dc786d869a95f7855f3108a82e30
@@ -30,6 +30,7 @@ class @Form
30
30
  @models.push options.model if options.model
31
31
  setComponent: (component, store) ->
32
32
  store ?= component.store
33
+ store.findOrCreate "Form", @
33
34
  @component = component
34
35
  @record = store.findOrCreate "Record", {}
35
36
  @changes = store.findOrCreate "Changes", {}
@@ -33,6 +33,7 @@ class @Model extends Observer
33
33
  Request[type](route, params)
34
34
  setDefaultActions: ->
35
35
  @setAction "find", @request "get"
36
+ @setAction "show", @request "get"
36
37
  @setAction "edit", @request "get"
37
38
  @setAction "update", @request "put", true
38
39
  @setAction "new", Request.none
@@ -0,0 +1,20 @@
1
+ model = Model.findOrCreate "Admin.Feedback", path: "feedback"
2
+ resolve = (r) ->
3
+ click = (e) ->
4
+ e.preventDefault()
5
+ model.update(r.id, { resolved: !r.resolved }).then (response) ->
6
+ message type: response.type, text: response.message
7
+ <a key="resolve" className="btn btn-primary btn-xs" href="#" onClick={click}>
8
+ {if r.resolved then "Unresolve" else "Resolve"}
9
+ </a>
10
+ model.actions = { show: true, resolve: resolve, destroy: true }
11
+ model.columns = [
12
+ { name: "name" },
13
+ { name: "email" },
14
+ { name: "subject" },
15
+ { name: "resolved", value: (r) -> if r.resolved then "Yes" else "No" },
16
+ { name: "created_at", value: (r) -> r.created_at.date() },
17
+ { name: "updated_at", value: (r) -> r.updated_at.date() }
18
+ ]
19
+
20
+ Component.create "Admin.Feedback.Index.Container", render: -> <Index.Container name="Admin.Feedback" />
@@ -1,4 +1,6 @@
1
1
  model = Model.findOrCreate "Admin.Page"
2
+ view = (r) -> <a key="visit" className="btn btn-primary btn-xs" href="/#{r.path}" target="_blank">Visit</a>
3
+ model.actions = { new: true, view: view, edit: true, destroy: true }
2
4
  model.columns = [
3
5
  { name: "active", value: (r) -> if r.active then "Yes" else "No" },
4
6
  { name: "rank" },
@@ -14,10 +16,7 @@ model.columns = [
14
16
  return "None" unless r.share_image.url
15
17
  <a href={r.share_image.url} target="_blank">View</a>
16
18
  },
17
- { name: "updated_at", value: (r) -> r.updated_at.date() },
18
- { name: "actions", edit: true, destroy: true, view: (r) ->
19
- <a key="visit" href="/#{r.path}" target="_blank">Visit</a>
20
- }
19
+ { name: "updated_at", value: (r) -> r.updated_at.date() }
21
20
  ]
22
21
 
23
22
  form = new Form "horizontal"
@@ -1,4 +1,5 @@
1
1
  model = Model.findOrCreate "Admin.Setting"
2
+ model.actions = { new: true, edit: true, destroy: true }
2
3
  model.columns = [
3
4
  { name: "name" },
4
5
  { name: "public", value: (r) -> if r.public then "Yes" else "No" },
@@ -12,8 +13,7 @@ model.columns = [
12
13
  when "Json" then "JSON"
13
14
  else r.value
14
15
  },
15
- { name: "updated_at", value: (r) -> r.updated_at.date() },
16
- { name: "actions", edit: true, destroy: true }
16
+ { name: "updated_at", value: (r) -> r.updated_at.date() }
17
17
  ]
18
18
 
19
19
  options = ["Boolean", "Json", "Text", "Uploader"]
@@ -1,10 +1,10 @@
1
1
  model = Model.findOrCreate "Admin.Sidebar"
2
+ model.actions = { new: true, edit: true, destroy: true }
2
3
  model.columns = [
3
4
  { name: "active", value: (r) -> if r.active then "Yes" else "No" },
4
5
  { name: "name" },
5
6
  { name: "heading" },
6
- { name: "updated_at", value: (r) -> r.updated_at.date() },
7
- { name: "actions", edit: true, destroy: true }
7
+ { name: "updated_at", value: (r) -> r.updated_at.date() }
8
8
  ]
9
9
 
10
10
  form = new Form "horizontal"
@@ -1,9 +1,9 @@
1
1
  model = Model.findOrCreate "Admin.Upload"
2
+ model.actions = { new: true, edit: true, destroy: true }
2
3
  model.columns = [
3
4
  { name: "name" },
4
5
  { name: "file", value: (r) -> <a href={r.file.url} target="_blank">View</a> },
5
- { name: "updated_at", value: (r) -> r.updated_at.date() },
6
- { name: "actions", edit: true, destroy: true }
6
+ { name: "updated_at", value: (r) -> r.updated_at.date() }
7
7
  ]
8
8
 
9
9
  form = new Form "horizontal"
@@ -1,4 +1,5 @@
1
1
  model = Model.findOrCreate "Admin.User"
2
+ model.actions = { new: true, edit: true, destroy: true }
2
3
  model.columns = [
3
4
  { name: "admin", value: (r) -> if r.admin then "Yes" else "No" },
4
5
  { name: "email" },
@@ -7,8 +8,7 @@ model.columns = [
7
8
  { name: "invited", value: (r) -> if r.invited then "Yes" else "No" },
8
9
  { name: "verified", value: (r) -> if r.verified then "Yes" else "No" },
9
10
  { name: "created_at", value: (r) -> r.created_at.date() },
10
- { name: "updated_at", value: (r) -> r.updated_at.date() },
11
- { name: "actions", edit: true, destroy: true }
11
+ { name: "updated_at", value: (r) -> r.updated_at.date() }
12
12
  ]
13
13
 
14
14
  form = new Form "horizontal"
@@ -8,8 +8,6 @@ Component.create "Index.Container",
8
8
  @follow @model.on "create", @modelCreate
9
9
  @follow @model.on "update", @modelUpdate
10
10
  @follow @model.on "destroy", @modelDestroy
11
- @newForm = @props.newForm || @props.form.copy()
12
- @editForm = @props.editForm || @props.form.copy()
13
11
  componentDidMount: ->
14
12
  @model.all()
15
13
  modelAll: (response) ->
@@ -23,20 +21,34 @@ Component.create "Index.Container",
23
21
  @model.all() if response.type == "danger"
24
22
  setPage: (page) ->
25
23
  @setState(page: 1, currentRecords: @state.records[(page*10 - 10)..page*10])
26
- new: (e) ->
27
- e.preventDefault()
28
- @model.new()
29
- false
30
- edit: (id, e) ->
31
- e.preventDefault()
32
- @model.edit(id)
33
- false
34
- destroy: (id, e) ->
35
- e.preventDefault()
36
- @model.destroy(id).then (response) ->
37
- message type: response.type, text: response.message
38
- false
24
+ actions: (record) ->
25
+ actions = []
26
+
27
+ for action, value of @model.actions when action != "new" && value
28
+ switch
29
+ when typeof value is "function"
30
+ actions.push value(record)
31
+ when action in ["show", "edit"]
32
+ modelAction = @model[action]
33
+ click = (e) ->
34
+ e.preventDefault()
35
+ modelAction(record.id)
36
+ actions.push <a key={action} className="btn btn-primary btn-xs" href="#" onClick={click}>{action.titleize}</a>
37
+ when action == "destroy"
38
+ destroy = @model.destroy
39
+ click = (e) ->
40
+ e.preventDefault()
41
+ destroy(record.id).then (response) -> message type: response.type, text: response.message
42
+ confirm = "Are you sure you want to delete #{record.name}?"
43
+ actions.push <a key="destroy" className="btn btn-primary btn-xs" href="#" onClick={click} data-confirm={confirm}>Delete</a>
44
+
45
+ <td>
46
+ <div className="btn-group">{actions}</div>
47
+ </td>
39
48
  render: ->
49
+ actions = @model.actions
50
+ actions = !!Object.keys(actions).find (action) -> action != "new" && actions[action]
51
+
40
52
  <div>
41
53
  <div className="row">
42
54
  <div className="col-xs-12">
@@ -44,7 +56,12 @@ Component.create "Index.Container",
44
56
  <div className="panel-heading">
45
57
  <h4>
46
58
  {@model.name.pluralize.titleize}
47
- <a className="btn btn-primary btn-xs" href="#" onClick={@new}>New</a>
59
+ {if @model.actions.new
60
+ click = (e) =>
61
+ e.preventDefault()
62
+ @model.new()
63
+ <a className="btn btn-primary btn-xs" href="#" onClick={click}>New</a>
64
+ }
48
65
  </h4>
49
66
  <Pagination page="1" total={@state.records.length} setPage={@setPage} />
50
67
  </div>
@@ -55,25 +72,16 @@ Component.create "Index.Container",
55
72
  {for field, i in @model.columns
56
73
  <th key={i}>{field.name.titleize}</th>
57
74
  }
75
+ {<th>Actions</th> if actions}
58
76
  </tr>
59
77
  </thead>
60
78
  <tbody>
61
79
  {for record, i in @state.records
62
80
  <tr key={i}>
63
81
  {for field, j in @model.columns
64
- if field.name == "actions"
65
- <td key={j}>
66
- {[
67
- field.view && field.view(record)
68
- field.view && field.edit && " | "
69
- field.edit && <a key="edit" onClick={@edit.bind(null, record.id)} href="#">Edit</a>
70
- field.destroy && " | "
71
- field.destroy && <a key="destroy" onClick={@destroy.bind(null, record.id)} href="#" data-confirm="Are you sure you want to delete #{record.name}?">Delete</a>
72
- ]}
73
- </td>
74
- else
75
- <td key={j}>{field.value?(record) ? record[field.name]}</td>
82
+ <td key={j}>{field.value?(record) ? record[field.name]}</td>
76
83
  }
84
+ {@actions(record) if actions}
77
85
  </tr>
78
86
  }
79
87
  </tbody>
@@ -82,6 +90,7 @@ Component.create "Index.Container",
82
90
  </div>
83
91
  </div>
84
92
  </div>
85
- <New.Container name={@props.name} form={@newForm} />
86
- <Edit.Container name={@props.name} form={@editForm} />
93
+ {<New.Container name={@props.name} form={@props.newForm || @props.form.copy()} /> if @model.actions.new}
94
+ {<Show.Container name={@props.name} /> if @model.actions.show}
95
+ {<Edit.Container name={@props.name} form={@props.editForm || @props.form.copy()} /> if @model.actions.edit}
87
96
  </div>
@@ -29,9 +29,9 @@ Component.create "Layout.PublicNavbar",
29
29
  <ul className="nav navbar-nav">
30
30
  {if setting "allow_signup"
31
31
  if @state.user.id
32
- @link(name: "Login", url: "/session")
33
- else
34
32
  @link(name: "Profile", url: "/profile")
33
+ else
34
+ @link(name: "Login", url: "/session")
35
35
  }
36
36
  {for page in @state.pages
37
37
  if page.children[0]
@@ -0,0 +1,39 @@
1
+ Model.create "Public.Feedback", path: "feedback"
2
+
3
+ form = new Form
4
+ form.add "name", "text"
5
+ form.add "email", "email"
6
+ form.add "subject", "text"
7
+ form.add "message", "textarea"
8
+
9
+ Component.create "Public.Feedback",
10
+ componentWillInitialize: ->
11
+ @model = Model.find "Public.Feedback"
12
+ @store = Store.findOrCreate "Public.Feedback"
13
+ @form = form.setComponent @
14
+ @follow @model.on "create", @modelCreate
15
+ @model.new()
16
+ modelCreate: (response) ->
17
+ message type: response.type, text: response.message
18
+ @form.changes.set {} if response.type == "success"
19
+ submit: (e) ->
20
+ e.preventDefault()
21
+ if @form.changes.empty()
22
+ message type: "warning", text: "You shall not pass!"
23
+ else
24
+ @model.create @form.changes.get()
25
+ false
26
+ render: ->
27
+ <div className="row text-center">
28
+ <div className="dynamic-sm">
29
+ <div>
30
+ <h3>Feedback</h3>
31
+ <form onSubmit={@submit}>
32
+ {@form.render()}
33
+ <div className="form-group">
34
+ <input type="submit" name="commit" value="Submit" className="btn btn-primary" />
35
+ </div>
36
+ </form>
37
+ </div>
38
+ </div>
39
+ </div>
@@ -7,7 +7,7 @@ Component.create "Public.Subscription",
7
7
  @store = Store.findOrCreate "Public.Subscription"
8
8
  @follow @model.on "destroy", @modelDestroy
9
9
  modelDestroy: (response) ->
10
- message type: type, text: response.message unless response.type == "success"
10
+ message type: response.type, text: response.message unless response.type == "success"
11
11
  @setState unsubscribed: true, message: response.message
12
12
  destroy: (e) ->
13
13
  e.preventDefault()
@@ -0,0 +1,60 @@
1
+ Component.create "Show.Container",
2
+ componentWillInitialize: ->
3
+ @model = Model.findOrCreate @props.name
4
+ @store = Store.findOrCreate "#{@props.name}.Show"
5
+ @follow @model.on "new", @hide
6
+ @follow @model.on "create", @hide
7
+ @follow @model.on "show", @show
8
+ @follow @model.on "edit", @hide
9
+ @follow @model.on "update", @hide
10
+ show: (response) ->
11
+ @store.merge(show: true, record: response.data)
12
+ hide: ->
13
+ @store.merge(show: false)
14
+ cancel: (e) ->
15
+ e.preventDefault()
16
+ @store.merge(show: false)
17
+ false
18
+ skipField: (field, value) ->
19
+ return true unless value?
20
+ return true if field == "id" || field.indexOf("_id") >= 0
21
+ return true if field.indexOf("password") >= 0
22
+ false
23
+ renderFields: (object) ->
24
+ switch
25
+ when object instanceof Array
26
+ for field in object
27
+ <div key={field} className="row">
28
+ <div className="col-xs-12">
29
+ {@renderFields field}
30
+ </div>
31
+ </div>
32
+ when object instanceof Object
33
+ for field, value of object when !@skipField(field, value)
34
+ <div key={field} className="row">
35
+ <label className="col-xs-3 text-right">
36
+ {field.titleize}
37
+ </label>
38
+ <div className="col-xs-9">
39
+ {@renderFields value}
40
+ </div>
41
+ </div>
42
+ when Date.parse(object)
43
+ object.date()
44
+ else
45
+ "#{object}"
46
+ render: ->
47
+ return <div /> unless @state.store.show
48
+ <div className="row">
49
+ <div className="col-xs-12">
50
+ <div className="panel panel-default">
51
+ <div className="panel-heading">
52
+ <h4>{@model.name.titleize}</h4>
53
+ <a className="btn btn-danger pull-right" href="#" onClick={@cancel}><i className="fa fa-close" /></a>
54
+ </div>
55
+ <div className="panel-body">
56
+ {@renderFields @state.store.record}
57
+ </div>
58
+ </div>
59
+ </div>
60
+ </div>
@@ -0,0 +1,2 @@
1
+ class Tomify::Admin::FeedbackController < Tomify.controllers.admin
2
+ end
@@ -0,0 +1,16 @@
1
+ class Tomify::Api::Admin::FeedbackController < Tomify.controllers.admin_api
2
+ def update
3
+ find_record
4
+ update_record
5
+ render json: { type: :success, data: data, message: "#{model_name} #{record.resolved ? "Resolved" : "Unresolved"}" }
6
+ end
7
+
8
+ private
9
+ def permitted_attributes
10
+ [:resolved]
11
+ end
12
+
13
+ def serializable_options
14
+ { include: [user: { only: [:first_name, :last_name, :email] }] }
15
+ end
16
+ end
@@ -1,4 +1,5 @@
1
1
  class Tomify::Api::Admin::PagesController < Tomify.controllers.admin_api
2
+ private
2
3
  def permitted_attributes
3
4
  [
4
5
  :parent_id, :sidebar_id,
@@ -1,4 +1,5 @@
1
1
  class Tomify::Api::Admin::SettingsController < Tomify.controllers.admin_api
2
+ private
2
3
  def permitted_attributes
3
4
  [:type, :name, :public, :value, json: {}]
4
5
  end
@@ -1,4 +1,5 @@
1
1
  class Tomify::Api::Admin::SidebarsController < Tomify.controllers.admin_api
2
+ private
2
3
  def permitted_attributes
3
4
  [:active, :name, :heading, :template, :text]
4
5
  end
@@ -1,4 +1,5 @@
1
1
  class Tomify::Api::Admin::UploadsController < Tomify.controllers.admin_api
2
+ private
2
3
  def permitted_attributes
3
4
  [:uuid, :name, :file, :size, :content_type]
4
5
  end
@@ -0,0 +1,15 @@
1
+ class Tomify::Api::Public::FeedbackController < Tomify.controllers.public_api
2
+ def create
3
+ create_record
4
+ render json: { type: :success, data: data, message: "Thank you for your feedback!" }
5
+ end
6
+
7
+ private
8
+ def permitted_attributes
9
+ [:name, :email, :subject, :message]
10
+ end
11
+
12
+ def record_params
13
+ super.merge(user_id: current_user.try(:id))
14
+ end
15
+ end
@@ -8,6 +8,7 @@ module Tomify::Concerns::Default::NavbarHelper
8
8
  add_to_navbar :public, Proc.new { Tomify.models.page.for_navbar }
9
9
  add_to_navbar :admin, [
10
10
  { name: "App", path: "admin/settings" },
11
+ { name: "Feedback", path: "admin/feedback" },
11
12
  { name: "Pages", path: "admin/pages" },
12
13
  { name: "Sidebars", path: "admin/sidebars" },
13
14
  { name: "Uploads", path: "admin/uploads" },
@@ -0,0 +1,5 @@
1
+ class Tomify::Public::FeedbackController < Tomify.controllers.public
2
+ def new
3
+ render component: "Public.Feedback"
4
+ end
5
+ end
@@ -0,0 +1,13 @@
1
+ class Tomify::FeedbackMailer < Tomify.mailers.base
2
+ def admin(feedback)
3
+ @feedback = feedback
4
+
5
+ mail to: Tomify.models.user.admin.pluck(:email), subject: "Feedback: #{@feedback.subject}"
6
+ end
7
+
8
+ def user(feedback)
9
+ @feedback = feedback
10
+
11
+ mail to: @feedback.email, subject: "Thank You!"
12
+ end
13
+ end
@@ -0,0 +1,23 @@
1
+ module Tomify::Concerns::Feedback
2
+ extend ActiveSupport::Concern
3
+
4
+ included do
5
+ belongs_to :user, class_name: Tomify.models.user.to_s, optional: true
6
+
7
+ after_create :notify_admin
8
+ after_create :notify_user
9
+
10
+ validates_presence_of :name, :email, :subject, :message
11
+
12
+ default_scope { order(:resolved, created_at: :desc) }
13
+ end
14
+
15
+ private
16
+ def notify_admin
17
+ Tomify.mailers.feedback.admin(self).deliver_now
18
+ end
19
+
20
+ def notify_user
21
+ Tomify.mailers.feedback.user(self).deliver_now
22
+ end
23
+ end
@@ -12,7 +12,7 @@ module Tomify::Concerns::Page
12
12
  before_validation :format_path
13
13
  before_validation :require_root, if: :root_changed?
14
14
  before_save :set_root, if: :root_changed?
15
- before_destroy { |page| page.root.blank? }
15
+ before_destroy { |page| throw :abort unless page.root.blank? }
16
16
 
17
17
  validates_presence_of :rank, :path, :name, :template
18
18
  validates_uniqueness_of :path
@@ -0,0 +1,3 @@
1
+ class Tomify::Feedback < Tomify.models.base
2
+ include Tomify::Concerns::Feedback
3
+ end
@@ -7,7 +7,7 @@ class Tomify::Setting < Tomify.models.base
7
7
  validate :public_valid?, on: :update
8
8
 
9
9
  after_commit :update_config
10
- before_destroy { |record| !record.name.in? self.class.required_settings }
10
+ before_destroy { |record| throw :abort if record.name.in? self.class.required_settings }
11
11
 
12
12
  def self.required_settings
13
13
  ["allow_signup", "aws", "name", "email", "timezone"]
@@ -0,0 +1 @@
1
+ = react_component "Public.Feedback"
@@ -0,0 +1,17 @@
1
+ %div(style="text-align: center;")
2
+ %p
3
+ #{setting :name} has recieved new feedback!
4
+ #{link_to "Login", root_url} to resolve it.
5
+ %div
6
+ %p
7
+ %b Name:
8
+ = @feedback.name
9
+ %p
10
+ %b Email:
11
+ = @feedback.email
12
+ %p
13
+ %b Subject:
14
+ = @feedback.subject
15
+ %p
16
+ %b Message
17
+ %p(style="white-space: pre-line;")= @feedback.message
@@ -0,0 +1,8 @@
1
+ %div(style="text-align: center;")
2
+ %p Dear #{@feedback.name},
3
+ %p Thank you for your feedback! You're the best!
4
+ = image_tag "tomify/gifs/woods.gif"
5
+ %p
6
+ Click #{link_to "here", root_url}
7
+ to come back home!
8
+ = render "partials/signature"
@@ -1,3 +1,4 @@
1
1
  - if @_message.to.length == 1
2
- To unsubscribe from all #{setting(:name)} emails
3
- = link_to "click here", subscription_url(email: @_message.to.first)
2
+ %div(style="text-align: center;")
3
+ To unsubscribe from all #{setting(:name)} emails
4
+ = link_to "click here", subscription_url(email: @_message.to.first)
@@ -1,9 +1,9 @@
1
1
  %div(style="text-align: center;")
2
2
  %p Dear #{@user.first_name},
3
3
  %p You've been invited to join #{setting(:name)}!
4
- = image_tag "gifs/woods.gif"
4
+ = image_tag "tomify/gifs/woods.gif"
5
5
  %p
6
6
  Click #{link_to "here", profile_url(token: @user.token(:email), from: :email)}
7
7
  to join!
8
- = image_tag "gifs/wind.gif"
8
+ = image_tag "tomify/gifs/wind.gif"
9
9
  = render "partials/signature"
@@ -1,13 +1,13 @@
1
1
  %div(style="text-align: center;")
2
2
  %p Dear #{@user.first_name},
3
3
  %p Looks like you forgot your password...
4
- = image_tag "gifs/laughing.gif"
5
- = image_tag "gifs/sneer.gif"
4
+ = image_tag "tomify/gifs/laughing.gif"
5
+ = image_tag "tomify/gifs/sneer.gif"
6
6
  %p Sounds like a rough day
7
- = image_tag "gifs/woods.gif"
8
- = image_tag "gifs/basketball.gif"
7
+ = image_tag "tomify/gifs/woods.gif"
8
+ = image_tag "tomify/gifs/basketball.gif"
9
9
  %p You'll do better next time
10
- = image_tag "gifs/wind.gif"
10
+ = image_tag "tomify/gifs/wind.gif"
11
11
  %p
12
12
  Guess you can update it
13
13
  = link_to "here", profile_url(token: @user.token(:email), from: :email)
@@ -1,9 +1,9 @@
1
1
  %div(style="text-align: center;")
2
2
  %p Dear #{@user.first_name},
3
3
  %p Welcome to #{setting(:name)}!
4
- = image_tag "gifs/woods.gif"
4
+ = image_tag "tomify/gifs/woods.gif"
5
5
  %p
6
6
  Click #{link_to "here", root_url(token: @user.token(:email), from: :email)}
7
7
  to come back home!
8
- = image_tag "gifs/wind.gif"
8
+ = image_tag "tomify/gifs/wind.gif"
9
9
  = render "partials/signature"
@@ -0,0 +1,3 @@
1
+ ActiveSupport::Inflector.inflections do |inflect|
2
+ inflect.irregular "feedback", "feedback"
3
+ end
data/config/routes.rb CHANGED
@@ -11,6 +11,7 @@ Rails.application.routes.draw do
11
11
  namespace :admin do
12
12
  root "settings#index"
13
13
 
14
+ resources :feedback, only: :index
14
15
  resources :pages, only: :index
15
16
  resources :settings, only: :index
16
17
  resources :sidebars, only: :index
@@ -20,6 +21,7 @@ Rails.application.routes.draw do
20
21
 
21
22
  namespace :api do
22
23
  namespace :admin do
24
+ resources :feedback, only: [:index, :show, :update, :destroy]
23
25
  resources :pages, only: [:index, :create, :show, :update, :destroy]
24
26
  resources :settings, only: [:index, :create, :show, :update, :destroy]
25
27
  resources :sidebars, only: [:index, :create, :show, :update, :destroy]
@@ -28,6 +30,7 @@ Rails.application.routes.draw do
28
30
  end
29
31
 
30
32
  namespace :public do
33
+ resource :feedback, only: :create
31
34
  resource :user, only: [:create, :show, :update, :destroy]
32
35
  resource :session, only: [:create, :destroy]
33
36
  resource :password, only: :create
@@ -0,0 +1,15 @@
1
+ class CreateFeedback < ActiveRecord::Migration[5.0]
2
+ def change
3
+ create_table :feedback do |t|
4
+ t.string :user_id
5
+ t.string :name, null: false
6
+ t.string :email, null: false
7
+ t.string :subject, null: false
8
+ t.string :message, null: false
9
+ t.boolean :resolved, default: false, null: false, index: true
10
+
11
+ t.timestamps
12
+ t.index [:resolved, :created_at]
13
+ end
14
+ end
15
+ end
data/db/seeds.rb CHANGED
@@ -10,7 +10,7 @@ if Tomify.models.setting.count.zero?
10
10
  debug Tomify::Setting::Json.create(name: "aws", value: {
11
11
  access_key: "",
12
12
  secret_key: "",
13
- bucket: "",
13
+ bucket: ""
14
14
  })
15
15
  debug Tomify::Setting::Json.create(name: "email", value: {
16
16
  username: "",
@@ -0,0 +1,14 @@
1
+ class Tomify::UserPreview < Tomify.previews.base
2
+ def admin
3
+ Tomify.mailers.feedback.admin(feedback)
4
+ end
5
+
6
+ def user
7
+ Tomify.mailers.feedback.user(feedback)
8
+ end
9
+
10
+ private
11
+ def feedback
12
+ Tomify.models.feedback.first
13
+ end
14
+ end
@@ -1,3 +1,3 @@
1
1
  module Tomify
2
- VERSION = "0.1.0"
2
+ VERSION = "0.1.1"
3
3
  end
data/lib/tomify.rb CHANGED
@@ -15,6 +15,7 @@ module Tomify
15
15
  mattr_accessor :mailers
16
16
  self.mailers = Constantly.new(
17
17
  base: "TomifyMailer",
18
+ feedback: "Tomify::FeedbackMailer",
18
19
  user: "Tomify::UserMailer"
19
20
  )
20
21
 
@@ -22,6 +23,7 @@ module Tomify
22
23
  self.models = Constantly.new(
23
24
  activity: "Tomify::Activity",
24
25
  base: "TomifyRecord",
26
+ feedback: "Tomify::Feedback",
25
27
  page: "Tomify::Page",
26
28
  setting: "Tomify::Setting",
27
29
  sidebar: "Tomify::Sidebar",
@@ -33,6 +35,7 @@ module Tomify
33
35
  mattr_accessor :previews
34
36
  self.previews = Constantly.new(
35
37
  base: "Tomify::Preview",
38
+ feedback: "Tomify::FeedbackPreview",
36
39
  user: "Tomify::UserPreview"
37
40
  )
38
41
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: tomify
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tom Prats
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-06-08 00:00:00.000000000 Z
11
+ date: 2017-06-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rails
@@ -265,6 +265,7 @@ files:
265
265
  - app/assets/javascripts/tomify/dynamic/classes/request.coffee
266
266
  - app/assets/javascripts/tomify/dynamic/classes/store.coffee
267
267
  - app/assets/javascripts/tomify/dynamic/global.coffee
268
+ - app/assets/javascripts/tomify/dynamic/react/components/admin/feedback.coffee
268
269
  - app/assets/javascripts/tomify/dynamic/react/components/admin/pages.coffee.erb
269
270
  - app/assets/javascripts/tomify/dynamic/react/components/admin/settings.coffee
270
271
  - app/assets/javascripts/tomify/dynamic/react/components/admin/sidebars.coffee.erb
@@ -288,6 +289,7 @@ files:
288
289
  - app/assets/javascripts/tomify/dynamic/react/components/layout/public_navbar.coffee
289
290
  - app/assets/javascripts/tomify/dynamic/react/components/new.coffee
290
291
  - app/assets/javascripts/tomify/dynamic/react/components/pagination.coffee
292
+ - app/assets/javascripts/tomify/dynamic/react/components/public/feedback.coffee
291
293
  - app/assets/javascripts/tomify/dynamic/react/components/public/passwords/new.coffee
292
294
  - app/assets/javascripts/tomify/dynamic/react/components/public/profile.coffee
293
295
  - app/assets/javascripts/tomify/dynamic/react/components/public/sessions/new.coffee
@@ -296,6 +298,7 @@ files:
296
298
  - app/assets/javascripts/tomify/dynamic/react/components/public/users/edit.coffee
297
299
  - app/assets/javascripts/tomify/dynamic/react/components/public/users/new.coffee
298
300
  - app/assets/javascripts/tomify/dynamic/react/components/public/users/show.coffee
301
+ - app/assets/javascripts/tomify/dynamic/react/components/show.coffee
299
302
  - app/assets/javascripts/tomify/dynamic/react/mixins/follow.coffee
300
303
  - app/assets/javascripts/tomify/dynamic/react/mixins/will-initialize.coffee
301
304
  - app/assets/javascripts/tomify/dynamic/react/mount.coffee
@@ -310,18 +313,21 @@ files:
310
313
  - app/assets/stylesheets/tomify/_pagination.scss
311
314
  - app/assets/stylesheets/tomify/_variables.scss
312
315
  - app/controllers/tomify/admin/controller.rb
316
+ - app/controllers/tomify/admin/feedback_controller.rb
313
317
  - app/controllers/tomify/admin/pages_controller.rb
314
318
  - app/controllers/tomify/admin/settings_controller.rb
315
319
  - app/controllers/tomify/admin/sidebars_controller.rb
316
320
  - app/controllers/tomify/admin/uploads_controller.rb
317
321
  - app/controllers/tomify/admin/users_controller.rb
318
322
  - app/controllers/tomify/api/admin/controller.rb
323
+ - app/controllers/tomify/api/admin/feedback_controller.rb
319
324
  - app/controllers/tomify/api/admin/pages_controller.rb
320
325
  - app/controllers/tomify/api/admin/settings_controller.rb
321
326
  - app/controllers/tomify/api/admin/sidebars_controller.rb
322
327
  - app/controllers/tomify/api/admin/uploads_controller.rb
323
328
  - app/controllers/tomify/api/admin/users_controller.rb
324
329
  - app/controllers/tomify/api/public/controller.rb
330
+ - app/controllers/tomify/api/public/feedback_controller.rb
325
331
  - app/controllers/tomify/api/public/passwords_controller.rb
326
332
  - app/controllers/tomify/api/public/sessions_controller.rb
327
333
  - app/controllers/tomify/api/public/subscriptions_controller.rb
@@ -337,6 +343,7 @@ files:
337
343
  - app/controllers/tomify/concerns/default/navbar_helper.rb
338
344
  - app/controllers/tomify/concerns/default/react_helper.rb
339
345
  - app/controllers/tomify/public/controller.rb
346
+ - app/controllers/tomify/public/feedback_controller.rb
340
347
  - app/controllers/tomify/public/pages_controller.rb
341
348
  - app/controllers/tomify/public/profiles_controller.rb
342
349
  - app/controllers/tomify/public/sessions_controller.rb
@@ -346,16 +353,19 @@ files:
346
353
  - app/helpers/tomify/email_helper.rb
347
354
  - app/helpers/tomify/render_helper.rb
348
355
  - app/helpers/tomify/timezone_helper.rb
356
+ - app/mailers/tomify/feedback_mailer.rb
349
357
  - app/mailers/tomify/user_mailer.rb
350
358
  - app/mailers/tomify_mailer.rb
351
359
  - app/models/tomify/activity.rb
352
360
  - app/models/tomify/concerns/activity.rb
361
+ - app/models/tomify/concerns/feedback.rb
353
362
  - app/models/tomify/concerns/page.rb
354
363
  - app/models/tomify/concerns/sidebar.rb
355
364
  - app/models/tomify/concerns/subscription.rb
356
365
  - app/models/tomify/concerns/token.rb
357
366
  - app/models/tomify/concerns/upload.rb
358
367
  - app/models/tomify/concerns/user.rb
368
+ - app/models/tomify/feedback.rb
359
369
  - app/models/tomify/page.rb
360
370
  - app/models/tomify/setting.rb
361
371
  - app/models/tomify/setting/boolean.rb
@@ -373,6 +383,7 @@ files:
373
383
  - app/uploaders/tomify_uploader.rb
374
384
  - app/views/templates/contact.haml
375
385
  - app/views/templates/default.haml
386
+ - app/views/templates/feedback.haml
376
387
  - app/views/templates/sidebar.haml
377
388
  - app/views/tomify/defaults/_body.haml
378
389
  - app/views/tomify/defaults/_container.haml
@@ -382,6 +393,8 @@ files:
382
393
  - app/views/tomify/defaults/_sharing.haml
383
394
  - app/views/tomify/layouts/application.haml
384
395
  - app/views/tomify/layouts/mailer.haml
396
+ - app/views/tomify/mailers/feedback_mailer/admin.haml
397
+ - app/views/tomify/mailers/feedback_mailer/user.haml
385
398
  - app/views/tomify/mailers/partials/_signature.haml
386
399
  - app/views/tomify/mailers/partials/_unsubscribe.haml
387
400
  - app/views/tomify/mailers/user_mailer/invite.haml
@@ -390,6 +403,7 @@ files:
390
403
  - config/initializers/assets.rb
391
404
  - config/initializers/database.rb
392
405
  - config/initializers/flash_patch.rb
406
+ - config/initializers/inflectors.rb
393
407
  - config/initializers/mailer.rb
394
408
  - config/initializers/renderers.rb
395
409
  - config/initializers/settings.rb
@@ -406,10 +420,12 @@ files:
406
420
  - db/migrate/19900000000009_add_invited_to_users.rb
407
421
  - db/migrate/19900000000010_add_template_to_sidebars.rb
408
422
  - db/migrate/19900000000011_create_activities.rb
423
+ - db/migrate/19900000000012_create_feedback.rb
409
424
  - db/seeds.rb
410
425
  - lib/generators/tomify/bundle/bundle_generator.rb
411
426
  - lib/generators/tomify/bundle/templates/default.js
412
427
  - lib/generators/tomify/bundle/templates/react.js
428
+ - lib/previews/tomify/feedback_preview.rb
413
429
  - lib/previews/tomify/preview.rb
414
430
  - lib/previews/tomify/user_preview.rb
415
431
  - lib/tasks/package.rake