cloudrider 0.3.21 → 0.3.22
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.
- checksums.yaml +4 -4
- data/generica/Gemfile +1 -1
- data/generica/Gemfile.lock +91 -51
- data/generica/app/assets/javascripts/components/product-display.js.em +4 -1
- data/generica/app/assets/javascripts/components/product-listing.js.em +4 -1
- data/generica/app/assets/javascripts/components/site-footer.js.em +12 -0
- data/generica/app/assets/javascripts/components/site-nav.js.em +15 -0
- data/generica/app/assets/javascripts/config/router.js.ls +18 -2
- data/generica/app/assets/javascripts/controllers/modals/fork_controller.js.em +4 -0
- data/generica/app/assets/javascripts/controllers/modals/login_controller.js.em +1 -4
- data/generica/app/assets/javascripts/controllers/modals/register_controller.js.em +1 -1
- data/generica/app/assets/javascripts/controllers/users/contact/edit_controller.js.em +16 -0
- data/generica/app/assets/javascripts/controllers/users/contacts/index_controller.js.em +21 -0
- data/generica/app/assets/javascripts/controllers/users/contacts/new_controller.js.em +16 -0
- data/generica/app/assets/javascripts/controllers/users/index_controller.js.em +19 -0
- data/generica/app/assets/javascripts/models/contact.js.em +11 -0
- data/generica/app/assets/javascripts/routes/users/contact_route.js.em +3 -0
- data/generica/app/assets/javascripts/routes/users/contacts/index_route.js.em +7 -0
- data/generica/app/assets/javascripts/routes/users/contacts/new_route.js.em +3 -0
- data/generica/app/assets/javascripts/routes/users/index_route.js.em +3 -0
- data/generica/app/assets/javascripts/templates/components/site-footer.emblem +18 -9
- data/generica/app/assets/javascripts/templates/users.emblem +11 -3
- data/generica/app/assets/javascripts/templates/users/contact/edit.emblem +16 -0
- data/generica/app/assets/javascripts/templates/users/contacts/_form-core.emblem +19 -0
- data/generica/app/assets/javascripts/templates/users/contacts/index.emblem +62 -0
- data/generica/app/assets/javascripts/templates/users/contacts/new.emblem +16 -0
- data/generica/app/assets/javascripts/templates/users/index.emblem +36 -2
- data/generica/app/assets/stylesheets/apiv1/components/_product-display.css.scss +7 -2
- data/generica/app/assets/stylesheets/apiv1/shared/_constants.css.scss +3 -0
- data/generica/app/controllers/apiv1/contacts/create_controller.rb +26 -0
- data/generica/app/controllers/apiv1/contacts/destroy_controller.rb +9 -0
- data/generica/app/controllers/apiv1/contacts/index_controller.rb +27 -0
- data/generica/app/controllers/apiv1/contacts/show_controller.rb +9 -0
- data/generica/app/controllers/apiv1/contacts/update_controller.rb +51 -0
- data/generica/app/controllers/apiv1/products/destroy_controller.rb +1 -1
- data/generica/app/models/admin/user.rb +20 -1
- data/generica/app/models/apiv1/user_contact.rb +51 -0
- data/generica/app/varissets/javascripts/templates/components/product-display.emblem.erb +34 -40
- data/generica/app/varissets/javascripts/templates/components/product-listing.emblem.erb +24 -16
- data/generica/app/varissets/javascripts/templates/components/site-nav.emblem.erb +12 -2
- data/generica/app/varissets/stylesheets/apiv1/components/_product-display.css.scss.erb +68 -31
- data/generica/app/varissets/stylesheets/apiv1/components/_product-listing.css.scss.erb +52 -14
- data/generica/config/routes.rb +5 -0
- data/generica/db/migrate/20141209185352_create_apiv1_user_contacts.rb +14 -0
- data/generica/spec/controllers/apiv1/contacts/update_controller_spec.rb +59 -0
- data/generica/spec/factories/admin/user_factory.rb +22 -4
- data/generica/spec/models/apiv1/user_contact_spec.rb +70 -0
- data/lib/cloudrider/version.rb +1 -1
- metadata +25 -2
@@ -0,0 +1,16 @@
|
|
1
|
+
class Apiv1.UsersContactEditController extends Ember.ObjectController
|
2
|
+
redirectOut: ->
|
3
|
+
@transitionToRoute 'users.contacts.index'
|
4
|
+
notifySuccess: ->
|
5
|
+
Apiv1.Flash.register "success", "contact updated!", 5000
|
6
|
+
successfulSave: (contact) ->
|
7
|
+
@notifySuccess()
|
8
|
+
@redirectOut()
|
9
|
+
failedSave: (reason) ->
|
10
|
+
Apiv1.Flash.register "warning", "contact unsccessful: #{reason.status}", 5000
|
11
|
+
@failureReason = Apiv1.HashEx.camelize reason.responseJSON if reason.responseJSON
|
12
|
+
|
13
|
+
actions:
|
14
|
+
formSubmitted: ->
|
15
|
+
@failureReason = null
|
16
|
+
@model.save().then(_.bind @successfulSave, @).catch(_.bind @failedSave, @)
|
@@ -0,0 +1,21 @@
|
|
1
|
+
class Apiv1.UsersContactsIndexController extends Ember.ObjectController
|
2
|
+
+computed model.@each.madePrimaryAt
|
3
|
+
primaryContact: ->
|
4
|
+
@model.rejectBy("madePrimaryAt", null).firstObject
|
5
|
+
|
6
|
+
+computed model.@each.id, primaryContact.id
|
7
|
+
secondaryContacts: ->
|
8
|
+
@model.rejectBy "id", @get("primaryContact.id")
|
9
|
+
|
10
|
+
successUpdate: (contact) ->
|
11
|
+
@transitionToRoute "users.index"
|
12
|
+
@transitionToRoute "users.contacts.index"
|
13
|
+
Apiv1.Flash.register "success", "successfully made primary", 5000
|
14
|
+
failedUpdate: (reason) ->
|
15
|
+
Apiv1.Flash.register "warning", "update failed: #{reason.status}", 5000
|
16
|
+
actions:
|
17
|
+
makePrimary: (contact) ->
|
18
|
+
contact.madePrimaryAt = new Date()
|
19
|
+
contact.save().then(_.bind @successUpdate, @).catch(_.bind @failedUpdate, @)
|
20
|
+
destroyContact: (contact) ->
|
21
|
+
contact.destroyRecord().then(_.bind @successUpdate, @).catch(_.bind @failedUpdate, @)
|
@@ -0,0 +1,16 @@
|
|
1
|
+
class Apiv1.UsersContactsNewController extends Ember.ObjectController
|
2
|
+
redirectOut: ->
|
3
|
+
@transitionToRoute 'users.contacts.index'
|
4
|
+
notifySuccess: ->
|
5
|
+
Apiv1.Flash.register "success", "contact created!", 5000
|
6
|
+
successfulSave: (contact) ->
|
7
|
+
@notifySuccess()
|
8
|
+
@redirectOut()
|
9
|
+
failedSave: (reason) ->
|
10
|
+
Apiv1.Flash.register "warning", "contact unsccessful: #{reason.status}", 5000
|
11
|
+
@failureReason = Apiv1.HashEx.camelize reason.responseJSON if reason.responseJSON
|
12
|
+
|
13
|
+
actions:
|
14
|
+
formSubmitted: ->
|
15
|
+
@failureReason = null
|
16
|
+
@model.save().then(_.bind @successfulSave, @).catch(_.bind @failedSave, @)
|
@@ -0,0 +1,19 @@
|
|
1
|
+
class Apiv1.UsersIndexController extends Ember.ObjectController
|
2
|
+
+computed model.firstObject
|
3
|
+
primaryContact: ->
|
4
|
+
@model.firstObject
|
5
|
+
|
6
|
+
+computed primaryContact.name, user.companyName
|
7
|
+
companyName: -> @get("primaryContact.name") or @get("user.companyName")
|
8
|
+
|
9
|
+
+computed primaryContact.email, user.email
|
10
|
+
email: -> @get("primaryContact.email") or @get("user.email")
|
11
|
+
|
12
|
+
+computed primaryContact.phone, user.phoneNumber
|
13
|
+
phoneNumber: -> @get("primaryContact.phone") or @get("user.phoneNumber")
|
14
|
+
|
15
|
+
+computed primaryContact.address, user.address
|
16
|
+
address: -> @get("primaryContact.address") or @get("user.address")
|
17
|
+
|
18
|
+
+computed Apiv1.CurrentUserSession.data
|
19
|
+
user: -> Apiv1.HashEx.camelize get$(Apiv1, "CurrentUserSession.data")
|
@@ -0,0 +1,11 @@
|
|
1
|
+
class Apiv1.Contact extends DS.Model
|
2
|
+
name: DS.attr "string"
|
3
|
+
phone: DS.attr "string"
|
4
|
+
email: DS.attr "string"
|
5
|
+
address: DS.attr "string"
|
6
|
+
madePrimaryAt: DS.attr "string"
|
7
|
+
deletedAt: DS.attr "date"
|
8
|
+
createdAt: DS.attr "date"
|
9
|
+
updatedAt: DS.attr "date"
|
10
|
+
|
11
|
+
user: DS.belongsTo "user", async: true
|
@@ -1,11 +1,20 @@
|
|
1
1
|
.row
|
2
|
-
.medium-
|
3
|
-
h1.footer-title
|
4
|
-
tr-span en="some company tagline"
|
5
|
-
.footer-divider
|
6
|
-
p.copyright <%= my_company_name %>. All Rights Reserved
|
7
|
-
.medium-pull-10.large-pull-10.large-2.medium-2.small-12.columns
|
2
|
+
.small-4.medium-3.large-2.column
|
8
3
|
select-locale class="lang-btn"
|
9
|
-
|
10
|
-
|
11
|
-
|
4
|
+
.small-4.medium-3.large-2.column
|
5
|
+
.center-vertical
|
6
|
+
.login
|
7
|
+
if adminLoggedIn
|
8
|
+
link-to "admin.index"
|
9
|
+
tr-span en="admin"
|
10
|
+
|
11
|
+
if userLoggedIn
|
12
|
+
link-to "users.index"
|
13
|
+
tr-span en="my account"
|
14
|
+
|
15
|
+
if notLoggedIn
|
16
|
+
.pointer click="displayModal 'login'"
|
17
|
+
tr-span en="login"
|
18
|
+
.small-4.medium-6.large-8.column
|
19
|
+
.center-vertical
|
20
|
+
.copyright <%= my_company_name %>. All Rights Reserved
|
@@ -6,18 +6,26 @@ section#user
|
|
6
6
|
tr-span en="user panel"
|
7
7
|
|
8
8
|
.row.admin-nav-tabs
|
9
|
-
.small-
|
9
|
+
.small-6.medium-3.large-2.columns
|
10
10
|
link-to "users.products.index" class="admin-nav-tab"
|
11
11
|
span.capitalize
|
12
12
|
tr-span en="my listings"
|
13
|
-
.small-
|
13
|
+
.small-6.medium-3.large-2.columns
|
14
14
|
link-to "users.products.new" class="admin-nav-tab"
|
15
15
|
span.capitalize
|
16
16
|
tr-span en="new listing"
|
17
|
-
.small-
|
17
|
+
.small-6.medium-3.large-2.columns
|
18
18
|
link-to "users.offers.index" class="admin-nav-tab"
|
19
19
|
span.capitalize
|
20
20
|
tr-span en="my offers"
|
21
|
+
.small-6.medium-3.large-2.columns
|
22
|
+
link-to "users.contacts.index" class="admin-nav-tab"
|
23
|
+
span.capitalize
|
24
|
+
tr-span en="my contact info"
|
25
|
+
.small-6.medium-3.large-2.columns.end
|
26
|
+
a.admin-nav-tab.pointer click="logoutUser"
|
27
|
+
span.capitalize
|
28
|
+
tr-span en="logout"
|
21
29
|
|
22
30
|
.row
|
23
31
|
.small-12.columns
|
@@ -0,0 +1,16 @@
|
|
1
|
+
.row
|
2
|
+
.small-6.medium-4.large-2.columns.end
|
3
|
+
link-to "users.contacts.index" class="button expand secondary"
|
4
|
+
i.fa.fa-chevron-left
|
5
|
+
span.capitalize.bold
|
6
|
+
tr-span en="back"
|
7
|
+
.row
|
8
|
+
.small-12.medium-10.large-8.columns.end
|
9
|
+
form-for errors=failureReason submit="formSubmitted"
|
10
|
+
== partial "users/contacts/form-core"
|
11
|
+
|
12
|
+
.button-forms
|
13
|
+
promise-button model=model class="button"
|
14
|
+
span.capitalize
|
15
|
+
i.fa.fa-check
|
16
|
+
tr-span en="submit"
|
@@ -0,0 +1,19 @@
|
|
1
|
+
.input-section attr-name="name"
|
2
|
+
label.form-label
|
3
|
+
tr-span en="company name"
|
4
|
+
Ember.TextField name="name" value=model.name placeholder="Acme Trade Co"
|
5
|
+
|
6
|
+
.input-section attr-name="email"
|
7
|
+
label.form-label
|
8
|
+
tr-span en="email"
|
9
|
+
Ember.TextField name="email" value=model.email placeholder="dog@example.co"
|
10
|
+
|
11
|
+
.input-section attr-name="phone"
|
12
|
+
label.form-label
|
13
|
+
tr-span en="phone number"
|
14
|
+
Ember.TextField name="phone" value=model.phone placeholder="(555) 123 - 1234"
|
15
|
+
|
16
|
+
.input-section attr-name="address"
|
17
|
+
label.form-label
|
18
|
+
tr-span en="company address"
|
19
|
+
Ember.TextField name="address" value=model.address placeholder="1234 Main Street, Beverly Hills, CA 90210"
|
@@ -0,0 +1,62 @@
|
|
1
|
+
.row
|
2
|
+
.small-12.medium-6.large-4.columns.end
|
3
|
+
link-to "users.contacts.new" class="button capitalize success expand"
|
4
|
+
tr-span en="add new contact"
|
5
|
+
.row
|
6
|
+
.small-12.medium-6.large-4.columns
|
7
|
+
if primaryContact
|
8
|
+
ul.pricing-table
|
9
|
+
li.title.capitalize click="makePrimary contact"
|
10
|
+
tr-span en="primary contact"
|
11
|
+
li.price= primaryContact.name
|
12
|
+
li.bullet-item
|
13
|
+
span.bold.colon
|
14
|
+
tr-span en="email"
|
15
|
+
span= primaryContact.email
|
16
|
+
li.bullet-item
|
17
|
+
span.bold.colon
|
18
|
+
tr-span en="phone"
|
19
|
+
span= primaryContact.phone
|
20
|
+
li.bullet-item
|
21
|
+
span.bold.colon
|
22
|
+
tr-span en="address"
|
23
|
+
span= primaryContact.address
|
24
|
+
li.description
|
25
|
+
span.bold.colon
|
26
|
+
tr-span en="created at"
|
27
|
+
span= primaryContact.createdAt
|
28
|
+
li.cta-button
|
29
|
+
link-to "users.contact.edit" primaryContact.id class="button capitalize"
|
30
|
+
i.fa.fa-edit
|
31
|
+
tr-span en="edit"
|
32
|
+
each contact in secondaryContacts
|
33
|
+
.small-12.medium-6.large-4.columns
|
34
|
+
ul.pricing-table
|
35
|
+
li.title.capitalize.pointer click="makePrimary contact"
|
36
|
+
tr-span en="contact"
|
37
|
+
span.parantheses
|
38
|
+
tr-span en="click to make primary"
|
39
|
+
li.price= contact.name
|
40
|
+
li.bullet-item
|
41
|
+
span.bold.colon
|
42
|
+
tr-span en="email"
|
43
|
+
span= contact.email
|
44
|
+
li.bullet-item
|
45
|
+
span.bold.colon
|
46
|
+
tr-span en="phone"
|
47
|
+
span= contact.phone
|
48
|
+
li.bullet-item
|
49
|
+
span.bold.colon
|
50
|
+
tr-span en="address"
|
51
|
+
span= contact.address
|
52
|
+
li.description
|
53
|
+
span.bold.colon
|
54
|
+
tr-span en="created at"
|
55
|
+
span= contact.createdAt
|
56
|
+
li.cta-button
|
57
|
+
link-to "users.contact.edit" contact.id class="button capitalize"
|
58
|
+
i.fa.fa-edit
|
59
|
+
tr-span en="edit"
|
60
|
+
button.button.alert.capitalize click="destroyContact contact"
|
61
|
+
i.fa.fa-times-circle
|
62
|
+
tr-span en="destroy"
|
@@ -0,0 +1,16 @@
|
|
1
|
+
.row
|
2
|
+
.small-6.medium-4.large-2.columns.end
|
3
|
+
link-to "users.index" class="button expand secondary"
|
4
|
+
i.fa.fa-chevron-left
|
5
|
+
span.capitalize.bold
|
6
|
+
tr-span en="back"
|
7
|
+
.row
|
8
|
+
.small-12.medium-10.large-8.columns.end
|
9
|
+
form-for errors=failureReason submit="formSubmitted"
|
10
|
+
== partial "users/contacts/form-core"
|
11
|
+
|
12
|
+
.button-forms
|
13
|
+
promise-button model=model class="button"
|
14
|
+
span.capitalize
|
15
|
+
i.fa.fa-check
|
16
|
+
tr-span en="submit"
|
@@ -1,3 +1,37 @@
|
|
1
|
-
|
1
|
+
.row
|
2
|
+
.small-12.columns
|
3
|
+
h4
|
4
|
+
span.capitalize
|
5
|
+
tr-span en="welcome"
|
6
|
+
span.prespace= companyName
|
7
|
+
.row
|
8
|
+
.small-12.columns
|
9
|
+
dl.company-info
|
10
|
+
dt
|
11
|
+
tr-span en="email"
|
12
|
+
dd
|
13
|
+
span= email
|
14
|
+
if user.userRank
|
15
|
+
dt
|
16
|
+
tr-span en="user rank"
|
17
|
+
dd
|
18
|
+
span= user.userRank
|
19
|
+
dt
|
20
|
+
tr-span en="company name"
|
21
|
+
dd
|
22
|
+
span= companyName
|
23
|
+
dt
|
24
|
+
tr-span en="phone number"
|
25
|
+
dd
|
26
|
+
span= phoneNumber
|
27
|
+
dt
|
28
|
+
tr-span en="address"
|
29
|
+
dd
|
30
|
+
span= address
|
31
|
+
dt
|
32
|
+
tr-span en="about me"
|
33
|
+
dd
|
34
|
+
span= user.aboutMe
|
35
|
+
|
36
|
+
|
2
37
|
|
3
|
-
p.todo TODO: analytics dashboard goes here
|
@@ -0,0 +1,26 @@
|
|
1
|
+
class Apiv1::Contacts::CreateController < Apiv1::UsersController
|
2
|
+
def create
|
3
|
+
if _contact_creation_success?
|
4
|
+
_contact.save!
|
5
|
+
render json: _contact_hash
|
6
|
+
else
|
7
|
+
render json: _error_hash, status: :expectation_failed
|
8
|
+
end
|
9
|
+
end
|
10
|
+
private
|
11
|
+
def _contact_hash
|
12
|
+
{ contact: _contact.to_ember_hash }
|
13
|
+
end
|
14
|
+
def _error_hash
|
15
|
+
{ contact: _contact.errors.to_h }
|
16
|
+
end
|
17
|
+
def _contact_creation_success?
|
18
|
+
_contact.valid?
|
19
|
+
end
|
20
|
+
def _contact
|
21
|
+
@contact ||= current_user.contacts.new _contact_params
|
22
|
+
end
|
23
|
+
def _contact_params
|
24
|
+
params.require(:contact).permit(:name, :phone, :email, :address)
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
class Apiv1::Contacts::IndexController < Apiv1::UsersController
|
2
|
+
def index
|
3
|
+
_search_index_process.call
|
4
|
+
end
|
5
|
+
private
|
6
|
+
def _search_index_process
|
7
|
+
_search_inputs >> (_consider_user_scope % Arrows::ID) >> _consider_primality >> _render_output
|
8
|
+
end
|
9
|
+
def _search_inputs
|
10
|
+
Arrows.lift [_user, _search_params]
|
11
|
+
end
|
12
|
+
def _consider_user_scope
|
13
|
+
Arrows.lift -> (user) { user.present? ? user.contacts : Apiv1::UserContact }
|
14
|
+
end
|
15
|
+
def _consider_primality
|
16
|
+
Arrows.lift -> (x) { x.last[:primary].present? ? x.first.is_primary.order_by_primality.limit(1) : x.first }
|
17
|
+
end
|
18
|
+
def _render_output
|
19
|
+
Arrows.lift -> (contacts) { render json: { contacts: contacts.map(&:to_ember_hash) } }
|
20
|
+
end
|
21
|
+
def _search_params
|
22
|
+
params.permit(:primary, :user_id)
|
23
|
+
end
|
24
|
+
def _user
|
25
|
+
Admin::User.find_by_id(_search_params[:user_id]) || current_user
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
class Apiv1::Contacts::UpdateController < Apiv1::UsersController
|
2
|
+
before_filter :_enforce_correct_user
|
3
|
+
def update
|
4
|
+
_update_process.call
|
5
|
+
end
|
6
|
+
private
|
7
|
+
def _enforce_correct_user
|
8
|
+
unless current_user.admin? || current_user.contacts.include?(_contact)
|
9
|
+
render json: { message: "This isn't your listing" }, status: 401
|
10
|
+
end
|
11
|
+
end
|
12
|
+
def _update_process
|
13
|
+
_user_inputs >> _apply_changes >> _decide_validity >> (_update_valid_data_process ^ _render_failure)
|
14
|
+
end
|
15
|
+
def _update_valid_data_process
|
16
|
+
_save_changes >> _decide_primality >> (_make_primary ^ Arrows::ID) >> _result_hashify >> _render_success
|
17
|
+
end
|
18
|
+
def _user_inputs
|
19
|
+
Arrows.lift _contact
|
20
|
+
end
|
21
|
+
def _apply_changes
|
22
|
+
Arrows.lift -> (contact) { contact.tap { |p| p.assign_attributes _contact_params } }
|
23
|
+
end
|
24
|
+
def _decide_validity
|
25
|
+
Arrows.lift -> (contact) { contact.valid? ? Arrows.good(contact) : Arrows.evil(contact) }
|
26
|
+
end
|
27
|
+
def _decide_primality
|
28
|
+
Arrows.lift -> (contact) { params[:contact][:made_primary_at].present? ? Arrows.good(contact) : Arrows.evil(contact) }
|
29
|
+
end
|
30
|
+
def _result_hashify
|
31
|
+
Arrows.lift -> (contact) { { contact: contact.to_ember_hash } }
|
32
|
+
end
|
33
|
+
def _render_success
|
34
|
+
Arrows.lift -> (result_hash) { render json: result_hash }
|
35
|
+
end
|
36
|
+
def _save_changes
|
37
|
+
Arrows.lift -> (contact) { contact.tap(&:save!) }
|
38
|
+
end
|
39
|
+
def _make_primary
|
40
|
+
Arrows.lift -> (contact) { contact.tap &:make_primary! }
|
41
|
+
end
|
42
|
+
def _render_failure
|
43
|
+
Arrows.lift -> (contact) { render json: contact.errors.to_h, status: :expectation_failed }
|
44
|
+
end
|
45
|
+
def _contact
|
46
|
+
@contact ||= Apiv1::UserContact.find params[:id]
|
47
|
+
end
|
48
|
+
def _contact_params
|
49
|
+
@contact_params ||= params.require(:contact).permit(:name, :phone, :email, :address)
|
50
|
+
end
|
51
|
+
end
|