diff options
Diffstat (limited to 'app')
32 files changed, 315 insertions, 104 deletions
diff --git a/app/controllers/application_controller.rb b/app/controllers/application_controller.rb index 35d6cb4..a4560e2 100644 --- a/app/controllers/application_controller.rb +++ b/app/controllers/application_controller.rb @@ -23,16 +23,6 @@ class ApplicationController < ActionController::Base json: {error: "The server failed to process your request. We'll look into it."} end - # - # Allows us to pass through bold text to flash messages. See format_flash() for where this is reversed. - # - # TODO: move to core - # - def bold(str) - "[b]#{str}[/b]" - end - helper_method :bold - ## ## LOCALE ## diff --git a/app/controllers/controller_extension/flash.rb b/app/controllers/controller_extension/flash.rb new file mode 100644 index 0000000..1642141 --- /dev/null +++ b/app/controllers/controller_extension/flash.rb @@ -0,0 +1,43 @@ +module ControllerExtension::Flash + extend ActiveSupport::Concern + + protected + + def flash_for(resource, options = {}) + return unless resource.changed? + add_flash_message_for resource + add_flash_errors_for resource if options[:with_errors] + end + + def add_flash_message_for(resource) + message = flash_message_for(resource) + type = flash_type_for(resource) + if message.present? + flash[type] = message + end + end + + def flash_message_for(resource) + I18n.t flash_i18n_key(resource), + scope: :flash, + cascade: true, + resource: resource.class.model_name.human + end + + def flash_i18n_key(resource) + namespace = [action_name] + namespace += controller_path.split('/') + namespace << flash_type_for(resource) + namespace.join(".") + end + + def flash_type_for(resource) + resource.valid? ? :success : :error + end + + def add_flash_errors_for(resource) + return if resource.valid? + flash[:error] += "<br>" + flash[:error] += resource.errors.full_messages.join(". <br>") + end +end diff --git a/app/controllers/controller_extension/token_authentication.rb b/app/controllers/controller_extension/token_authentication.rb index 6e0a6ce..b0ed624 100644 --- a/app/controllers/controller_extension/token_authentication.rb +++ b/app/controllers/controller_extension/token_authentication.rb @@ -2,8 +2,8 @@ module ControllerExtension::TokenAuthentication extend ActiveSupport::Concern def token - @token ||= authenticate_with_http_token do |token_id, options| - Token.find(token_id) + @token ||= authenticate_with_http_token do |token, options| + Token.find_by_token(token) end end diff --git a/app/controllers/errors_controller.rb b/app/controllers/errors_controller.rb new file mode 100644 index 0000000..6c659e6 --- /dev/null +++ b/app/controllers/errors_controller.rb @@ -0,0 +1,10 @@ +# We render http errors ourselves so we can customize them +class ErrorsController < ApplicationController + # 404 + def not_found + end + + # 500 + def server_error + end +end diff --git a/app/controllers/v1/certs_controller.rb b/app/controllers/v1/certs_controller.rb index 73409ef..b6d1d0b 100644 --- a/app/controllers/v1/certs_controller.rb +++ b/app/controllers/v1/certs_controller.rb @@ -3,7 +3,15 @@ class V1::CertsController < ApplicationController before_filter :require_login, :unless => :anonymous_certs_allowed? # GET /cert + # deprecated - we actually create a new cert and that can + # be reflected in the action. GET /cert will eventually go + # away and be replaced by POST /cert def show + create + end + + # POST /cert + def create @cert = ClientCertificate.new(:prefix => service_level.cert_prefix) render text: @cert.to_s, content_type: 'text/plain' end diff --git a/app/controllers/v1/smtp_certs_controller.rb b/app/controllers/v1/smtp_certs_controller.rb new file mode 100644 index 0000000..377a49c --- /dev/null +++ b/app/controllers/v1/smtp_certs_controller.rb @@ -0,0 +1,37 @@ +class V1::SmtpCertsController < ApplicationController + + before_filter :require_login + before_filter :require_email_account + before_filter :fetch_identity + + # POST /1/smtp_cert + def create + @cert = ClientCertificate.new prefix: current_user.email_address + @identity.register_cert(@cert) + @identity.save + render text: @cert.to_s, content_type: 'text/plain' + end + + protected + + # + # Filters + # + + def require_email_account + access_denied unless service_level.provides? 'email' + end + + def fetch_identity + @identity = current_user.identity + end + + # + # Helper methods + # + + def service_level + current_user.effective_service_level + end + +end diff --git a/app/helpers/application_helper.rb b/app/helpers/application_helper.rb index 90e649a..6de5e1b 100644 --- a/app/helpers/application_helper.rb +++ b/app/helpers/application_helper.rb @@ -40,8 +40,9 @@ module ApplicationHelper end end + # fairly strict sanitation for flash messages def format_flash(msg) - html_escape(msg).gsub('[b]', '<b>').gsub('[/b]', '</b>').html_safe + sanitize(msg, tags: %w(em strong b br), attributes: []) end end diff --git a/app/helpers/core_helper.rb b/app/helpers/core_helper.rb index 4126906..46e8fa4 100644 --- a/app/helpers/core_helper.rb +++ b/app/helpers/core_helper.rb @@ -10,4 +10,11 @@ module CoreHelper render 'common/home_page_buttons' end + # + # returns true if the configured service levels contain a level with a price attached + # + def paid_service_level? + APP_CONFIG[:service_levels].present? && APP_CONFIG[:service_levels].detect{|k,v| v['rate'].present?} + end + end diff --git a/app/helpers/link_helper.rb b/app/helpers/link_helper.rb new file mode 100644 index 0000000..55e392b --- /dev/null +++ b/app/helpers/link_helper.rb @@ -0,0 +1,49 @@ +module LinkHelper + + # + # markup for bootstrap button + # + # takes same arguments as link_to and adds a 'btn' class. + # In addition: + # * the name will be translated if it is a symbol + # * html_options[:type] will be converted into a btn-type class + # + # example: + # btn :home, home_path, type: [:large, :primary] + # + def btn(*args, &block) + html_options = extract_html_options!(args, &block) + type = Array(html_options.delete(:type)) + type.map! {|t| "btn-#{t}"} + html_options[:class] = concat_classes(html_options[:class], 'btn', type) + args[0] = t(args[0]) if args[0].is_a?(Symbol) + link_to *args, html_options, &block + end + + def destroy_btn(*args, &block) + html_options = extract_html_options!(args, &block) + confirmation = t "#{controller_symbol}.confirm.destroy.are_you_sure", + cascade: true + html_options.merge! method: :delete, confirm: confirmation + btn *args, html_options, &block + end + + # + # concat_classes will combine classes in a fairly flexible way. + # it can handle nil, arrays, space separated strings + # it returns a space separated string of classes. + def concat_classes(*classes) + classes.compact! + classes.map {|c| c.respond_to?(:split) ? c.split(' ') : c } + classes.flatten! + classes.join ' ' + end + + def extract_html_options!(args) + if args.count > 2 or args.count > 1 && block_given? + args.extract_options! + else + {} + end + end +end diff --git a/app/models/account.rb b/app/models/account.rb index cf998e4..32ed445 100644 --- a/app/models/account.rb +++ b/app/models/account.rb @@ -16,9 +16,13 @@ class Account # Returns the user record so it can be used in views. def self.create(attrs) - @user = User.create(attrs).tap do |user| - Identity.create_for user + @user = User.create(attrs) + if @user.persisted? + identity = @user.identity + identity.user_id = @user.id + identity.save end + return @user end def update(attrs) diff --git a/app/models/client_certificate.rb b/app/models/client_certificate.rb index 76b07a2..63de9e1 100644 --- a/app/models/client_certificate.rb +++ b/app/models/client_certificate.rb @@ -43,8 +43,16 @@ class ClientCertificate self.key.to_pem + self.cert.to_pem end + def fingerprint + OpenSSL::Digest::SHA1.hexdigest(openssl_cert.to_der).scan(/../).join(':') + end + private + def openssl_cert + cert.openssl_body + end + def self.root_ca @root_ca ||= begin crt = File.read(APP_CONFIG[:client_ca_cert]) diff --git a/app/models/email.rb b/app/models/email.rb index a9a503f..4090275 100644 --- a/app/models/email.rb +++ b/app/models/email.rb @@ -7,6 +7,11 @@ class Email < String :message => "needs to be a valid email address" } + # Make sure we can call Email.new(nil) and get an invalid email address + def initialize(s) + super(s.to_s) + end + def to_partial_path "emails/email" end diff --git a/app/models/identity.rb b/app/models/identity.rb index ad8c01e..2f6241c 100644 --- a/app/models/identity.rb +++ b/app/models/identity.rb @@ -8,9 +8,12 @@ class Identity < CouchRest::Model::Base property :address, LocalEmail property :destination, Email property :keys, HashWithIndifferentAccess + property :cert_fingerprints, Hash - validate :unique_forward - validate :alias_available + validates :address, presence: true + validate :address_available + validates :destination, presence: true, if: :enabled? + validates :destination, uniqueness: {scope: :address} validate :address_local_email validate :destination_email @@ -49,7 +52,8 @@ class Identity < CouchRest::Model::Base def self.find_for(user, attributes = {}) attributes.reverse_merge! attributes_from_user(user) - find_by_address_and_destination [attributes[:address], attributes[:destination]] + id = find_by_address_and_destination attributes.values_at(:address, :destination) + return id if id && id.user == user end def self.build_for(user, attributes = {}) @@ -66,7 +70,9 @@ class Identity < CouchRest::Model::Base def self.disable_all_for(user) Identity.by_user_id.key(user.id).each do |identity| identity.disable - identity.save + # if the identity is not unique anymore because the destination + # was reset to nil we destroy it. + identity.save || identity.destroy end end @@ -90,7 +96,11 @@ class Identity < CouchRest::Model::Base end def enabled? - self.destination && self.user_id + self.user_id + end + + def disabled? + !enabled? end def disable @@ -107,36 +117,50 @@ class Identity < CouchRest::Model::Base write_attribute('keys', keys.merge(type => key.to_s)) end + def cert_fingerprints + read_attribute('cert_fingerprints') || Hash.new + end + + def register_cert(cert) + today = DateTime.now.to_date.to_s + write_attribute 'cert_fingerprints', + cert_fingerprints.merge(cert.fingerprint => today) + end + # for LoginFormatValidation def login - self.address.handle + address.handle if address.present? end protected - def unique_forward - same = Identity.find_by_address_and_destination([address, destination]) - if same && same != self - errors.add :base, "This alias already exists" + def address_available + blocking_identities = Identity.by_address.key(address).all + blocking_identities.delete self + if self.user + blocking_identities.reject! { |other| other.user == self.user } end - end - - def alias_available - same = Identity.find_by_address(address) - if same && same.user != self.user - errors.add :base, "This email has already been taken" + if blocking_identities.any? + errors.add :address, :taken end end def address_local_email - return if address.valid? #this ensures it is LocalEmail - self.errors.add(:address, address.errors.messages[:email].first) #assumes only one error + # caught by presence validation + return if address.blank? + return if address.valid? + address.errors.each do |attribute, error| + self.errors.add(:address, error) + end end def destination_email - return if destination.nil? # this identity is disabled - return if destination.valid? # this ensures it is Email - self.errors.add(:destination, destination.errors.messages[:email].first) #assumes only one error #TODO + # caught by presence validation or this identity is disabled + return if destination.blank? + return if destination.valid? + destination.errors.each do |attribute, error| + self.errors.add(:destination, error) + end end end diff --git a/app/models/local_email.rb b/app/models/local_email.rb index 2b4c65e..ded7baf 100644 --- a/app/models/local_email.rb +++ b/app/models/local_email.rb @@ -58,11 +58,9 @@ class LocalEmail < Email end def handle_in_passwd? - begin - !!Etc.getpwnam(handle) - rescue ArgumentError - # handle was not found - return false - end + Etc.getpwnam(handle).present? + rescue ArgumentError + # handle was not found + return false end end diff --git a/app/models/pgp_key.rb b/app/models/pgp_key.rb index 66f8660..3384f4c 100644 --- a/app/models/pgp_key.rb +++ b/app/models/pgp_key.rb @@ -25,9 +25,10 @@ class PgpKey # allow comparison with plain keyblock strings. def ==(other) + return false if (self.present? != other.present?) self.equal?(other) or # relax the comparison on line ends. - self.to_s.tr_s("\n\r", '') == other.tr_s("\r\n", '') + self.to_s.tr_s("\n\r", '') == other.tr_s("\n\r", '') end protected diff --git a/app/models/token.rb b/app/models/token.rb index e759ee3..ff2ad12 100644 --- a/app/models/token.rb +++ b/app/models/token.rb @@ -1,3 +1,5 @@ +require 'digest/sha2' + class Token < CouchRest::Model::Base use_database :tokens @@ -11,10 +13,16 @@ class Token < CouchRest::Model::Base validates :user_id, presence: true + attr_accessor :token + design do view :by_last_seen_at end + def self.find_by_token(token) + self.find Digest::SHA512.hexdigest(token) + end + def self.expires_after APP_CONFIG[:auth] && APP_CONFIG[:auth][:token_expires_after] end @@ -31,7 +39,7 @@ class Token < CouchRest::Model::Base end def to_s - id + token end def authenticate @@ -65,7 +73,8 @@ class Token < CouchRest::Model::Base def initialize(*args) super if new_record? - self.id = SecureRandom.urlsafe_base64(32).gsub(/^_*/, '') + self.token = SecureRandom.urlsafe_base64(32).gsub(/^_*/, '') + self.id = Digest::SHA512.hexdigest(self.token) self.last_seen_at = Time.now end end diff --git a/app/models/user.rb b/app/models/user.rb index 6678de6..f8b9ddc 100644 --- a/app/models/user.rb +++ b/app/models/user.rb @@ -24,7 +24,7 @@ class User < CouchRest::Model::Base :uniqueness => true, :if => :serverside? - validate :login_is_unique_alias + validate :identity_is_valid validates :password_salt, :password_verifier, :format => { :with => /\A[\dA-Fa-f]+\z/, :message => "Only hex numbers allowed" } @@ -42,6 +42,11 @@ class User < CouchRest::Model::Base view :by_created_at end # end of design + def reload + @identity = nil + super + end + def to_json(options={}) { :login => login, @@ -161,11 +166,10 @@ class User < CouchRest::Model::Base # Validation Functions ## - def login_is_unique_alias - alias_identity = Identity.find_by_address(self.email_address) - return if alias_identity.blank? - if alias_identity.user != self - errors.add(:login, "has already been taken") + def identity_is_valid + return if identity.valid? + identity.errors.each do |attribute, error| + self.errors.add(:login, error) end end diff --git a/app/views/common/_action_buttons.html.haml b/app/views/common/_action_buttons.html.haml index c74fcd1..266abe1 100644 --- a/app/views/common/_action_buttons.html.haml +++ b/app/views/common/_action_buttons.html.haml @@ -1,11 +1,11 @@ .home-buttons .row-fluid.second .login.span4 - %span.link= link_to(icon('ok-sign', icon_color) + t(:login), login_path, :class => 'btn') - %span.info= t(:login_info) + %span.link= btn icon('ok-sign') + t(:login), login_path + %span.info= t(:login_info, default: "") .signup.span4 - %span.link= link_to(icon('user', icon_color) + t(:signup), signup_path, :class => 'btn') - %span.info= t(:signup_info) + %span.link= btn icon('user') + t(:signup), signup_path + %span.info= t(:signup_info, default: "") .help.span4 - %span.link= link_to(icon('question-sign', icon_color) + t(:get_help), new_ticket_path, :class => 'btn') - %span.info= t(:help_info) + %span.link= btn icon('question-sign') + t(:get_help), new_ticket_path + %span.info= t(:support_info, default: "") diff --git a/app/views/common/_download_button.html.haml b/app/views/common/_download_button.html.haml index e57c56b..9c26860 100644 --- a/app/views/common/_download_button.html.haml +++ b/app/views/common/_download_button.html.haml @@ -2,7 +2,7 @@ .row-fluid.first .span2 .download.span8 - = link_to client_download_url, class: "btn btn-large btn-primary" do + = btn client_download_url, type: [:large, :primary] do = big_icon('download') - = t(:download_client) + = t(:download_bitmask) .span2 diff --git a/app/views/common/_home_page_buttons.html.haml b/app/views/common/_home_page_buttons.html.haml index 8c47983..fc6348e 100644 --- a/app/views/common/_home_page_buttons.html.haml +++ b/app/views/common/_home_page_buttons.html.haml @@ -1,8 +1,6 @@ -- icon_color = :black - = render 'common/download_button' - if local_assigns[:divider] .row-fluid .span12 = render local_assigns[:divider] -= render 'common/action_buttons', icon_color: icon_color += render 'common/action_buttons' diff --git a/app/views/errors/not_found.html.haml b/app/views/errors/not_found.html.haml new file mode 100644 index 0000000..c7fec22 --- /dev/null +++ b/app/views/errors/not_found.html.haml @@ -0,0 +1,7 @@ +.hero-unit + %h1=t 'errors.title.page_not_found' + %h2=t 'errors.subtitle.page_not_found', default: '' + %p.lead=t 'errors.text.page_not_found', default: '' + %a.btn.btn-primary.btn-large{href:'/'} + %i.icon-home.icon-white + =t :home diff --git a/app/views/errors/server_error.html.haml b/app/views/errors/server_error.html.haml new file mode 100644 index 0000000..a4133da --- /dev/null +++ b/app/views/errors/server_error.html.haml @@ -0,0 +1,7 @@ +.hero-unit + %h1=t 'errors.title.server_error' + %h2=t 'errors.subtitle.server_error', default: '' + %p.lead=t 'errors.text.server_error', default: '' + %a.btn.btn-primary.btn-large{href:'/'} + %i.icon-home.icon-white + =t :home diff --git a/app/views/layouts/_footer.html.haml b/app/views/layouts/_footer.html.haml index 340d36c..de53667 100644 --- a/app/views/layouts/_footer.html.haml +++ b/app/views/layouts/_footer.html.haml @@ -6,5 +6,5 @@ = link_to icon('info-sign') + t(:about), about_path - if lookup_context.exists?('pages/contact') = link_to icon('comment') + t(:contact), contact_path - - if APP_CONFIG[:service_levels].present? + - if paid_service_level? = link_to icon('shopping-cart') + t(:pricing), pricing_path diff --git a/app/views/layouts/_header.html.haml b/app/views/layouts/_header.html.haml index a1dd47a..e827f60 100644 --- a/app/views/layouts/_header.html.haml +++ b/app/views/layouts/_header.html.haml @@ -2,9 +2,9 @@ %ul.nav.nav-tabs = # this navigation isn't quite right. also, we will want to active for an identity controller once it is added. %li{:class => ("active" if controller?('users', 'overviews') || params[:user_id])} - = link_to t(:users), users_path + = link_to t(".users"), users_path %li{:class => ("active" if controller?('tickets') && !params[:user_id])} - = link_to t(:tickets), tickets_path + = link_to t(".tickets", cascade: true), tickets_path %li = link_to t(:logout), logout_path, :method => :delete - if @user && @show_navigation diff --git a/app/views/layouts/_messages.html.haml b/app/views/layouts/_messages.html.haml index 7ff985f..18be54f 100644 --- a/app/views/layouts/_messages.html.haml +++ b/app/views/layouts/_messages.html.haml @@ -1,6 +1,6 @@ #messages - flash.each do |name, msg| - if msg.is_a?(String) - %div{:class => "alert alert-#{name == :notice ? "success" : "error"}"} + %div{:class => "alert alert-#{name == :notice ? "success" : name}"} %a.close{"data-dismiss" => "alert"} × = content_tag :div, format_flash(msg), :id => "flash_#{name}" diff --git a/app/views/layouts/_navigation.html.haml b/app/views/layouts/_navigation.html.haml index b81c43d..94f71f7 100644 --- a/app/views/layouts/_navigation.html.haml +++ b/app/views/layouts/_navigation.html.haml @@ -2,6 +2,6 @@ = link_to_navigation t(:overview), @user, :active => (controller?(:users) && action?(:show)) = link_to_navigation t(:account_settings), edit_user_path(@user), :active => (controller?(:users) && !action?(:show)) - # will want link for identity settings - = link_to_navigation t(:support_tickets), auto_tickets_path, :active => controller?(:tickets) + = link_to_navigation t(".tickets"), auto_tickets_path, :active => controller?(:tickets) = link_to_navigation t(:billing_settings), billing_top_link(@user), :active => controller?(:customer, :payments, :subscriptions, :credit_card_info) if APP_CONFIG[:billing] = link_to_navigation t(:logout), logout_path, :method => :delete diff --git a/app/views/pages/pricing.html.haml b/app/views/pages/pricing.html.haml index e339d27..983501e 100644 --- a/app/views/pages/pricing.html.haml +++ b/app/views/pages/pricing.html.haml @@ -1,5 +1,5 @@ %h1= t(:pricing) -%p= link_to(icon('user') + t(:signup), signup_path, :class => 'btn') +%p= btn icon('user') + t(:signup), signup_path - levels = APP_CONFIG[:service_levels] - if levels diff --git a/app/views/pages/terms-of-service.en.md b/app/views/pages/terms-of-service.en.md index 7b57027..93490b7 100644 --- a/app/views/pages/terms-of-service.en.md +++ b/app/views/pages/terms-of-service.en.md @@ -3,8 +3,8 @@ This document is our Terms of Service, which describes what activities are allowed, under what conditions we may terminate your account, and asserts our limited liability. It applies to all interactions with **<%=APP_CONFIG[:domain]%>**. Your use of **<%=APP_CONFIG[:domain]%>** services will constitute your agreement to these Terms of Service. <p class="alert alert-info"> - <b>Summary:</b><br/> - (1) If you do anything truly evil, we will terminate your account.<br/> + <b>Summary:</b><br> + (1) If you do anything truly evil, we will terminate your account.<br> (2) We are not liable for any damages related to the use of this service. </p> diff --git a/app/views/users/_destroy_account.html.haml b/app/views/users/_destroy_account.html.haml index 445f3c4..a2c4ddd 100644 --- a/app/views/users/_destroy_account.html.haml +++ b/app/views/users/_destroy_account.html.haml @@ -8,20 +8,20 @@ - else = t(:admin_destroy_account, :username => @user.login) %p= t(:destroy_account_info) -= link_to user_path(@user), :method => :delete, :confirm => t(:are_you_sure), :class => "btn btn-danger" do += destroy_btn user_path(@user), :type => "danger" do %i.icon-remove.icon-white = t(:destroy_my_account) - if @user != current_user and @user.enabled? %legend = t(:deactivate_account, :username => @user.login) %p= t(:deactivate_description) - = link_to deactivate_user_path(@user), :method => :post, :class => "btn btn-warning" do + = btn deactivate_user_path(@user), :method => :post, :type => "warning" do %i.icon-pause.icon-white = t(:deactivate) - elsif @user != current_user and !@user.enabled? %legend = t(:enable_account, :username => @user.login) %p= t(:enable_description) - = link_to enable_user_path(@user), :method => :post, :class => "btn btn-warning" do + = btn enable_user_path(@user), :method => :post, :type => "warning" do %i.icon-ok.icon-white = t(:enable) diff --git a/app/views/users/_overview.html.haml b/app/views/users/_overview.html.haml new file mode 100644 index 0000000..e38fdc8 --- /dev/null +++ b/app/views/users/_overview.html.haml @@ -0,0 +1,24 @@ +.overview + + %h2.first= t(".welcome", username: @user.login, cascade: true) + + - if admin? + %p + = t(:created) + = @user.created_at + %br + = t(:updated) + = @user.updated_at + %br + = t(:enabled) + = @user.enabled? + + %p= t(:overview_intro, default: "") + + %ul.unstyled + %li= icon('user') + link_to(t(".account"), edit_user_path(@user)) + - # %li= icon('envelope') + link_to(t(:overview_email), {insert path for user identities, presuambly} + %li= icon('question-sign') + link_to(t(".tickets"), user_tickets_path(@user)) + %li= icon('shopping-cart') + link_to(t(".billing"), billing_top_link(@user)) if APP_CONFIG[:billing] + + diff --git a/app/views/users/new.html.haml b/app/views/users/new.html.haml index bc36068..41a9d55 100644 --- a/app/views/users/new.html.haml +++ b/app/views/users/new.html.haml @@ -17,5 +17,5 @@ = f.input :login, :label => t(:username), :required => false, :input_html => { :id => :srp_username } = f.input :password, :required => false, :validate => true, :input_html => { :id => :srp_password } = f.input :password_confirmation, :required => false, :validate => true, :input_html => { :id => :srp_password_confirmation } - = f.button :wrapped, value: t(:signup), cancel: home_path + = f.button :wrapped, cancel: home_path diff --git a/app/views/users/show.html.haml b/app/views/users/show.html.haml index ddc33ab..da8e467 100644 --- a/app/views/users/show.html.haml +++ b/app/views/users/show.html.haml @@ -1,30 +1,7 @@ -.overview - - %h2.first= t(:overview_welcome, :username => @user.login) - - - if admin? - %p - = t(:created) - = @user.created_at - %br - = t(:updated) - = @user.updated_at - %br - = t(:enabled) - = @user.enabled? - - %p= t(:overview_intro) - - %ul.unstyled - %li= icon('user') + link_to(t(:overview_account), edit_user_path(@user)) - - # %li= icon('envelope') + link_to(t(:overview_email), {insert path for user identities, presuambly} - %li= icon('question-sign') + link_to(t(:overview_tickets), user_tickets_path(@user)) - %li= icon('shopping-cart') + link_to(t(:overview_billing), billing_top_link(@user)) if APP_CONFIG[:billing] - - - .container-fluid - .row-fluid - %h4 To use bitmask services: - = link_to client_download_url, class: "btn btn-primary" do - %i.icon-arrow-down.icon-white - = t(:download_client) += render 'overview' +.container-fluid + .row-fluid + %h4 To use bitmask services: + = btn client_download_url, type: "primary" do + %i.icon-arrow-down.icon-white + = t(:download_bitmask) |